pa_linux_alsa.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,692 行 · 第 1/5 页
C
1,692 行
/* * $Id: pa_linux_alsa.c,v 1.1.2.71 2005/04/15 18:20:18 aknudsen Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * ALSA implementation by Joshua Haberman and Arve Knudsen * * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> * Copyright (c) 2005 Arve Knudsen <aknuds-1@broadpark.no> * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#define ALSA_PCM_NEW_HW_PARAMS_API#define ALSA_PCM_NEW_SW_PARAMS_API#include <alsa/asoundlib.h>#undef ALSA_PCM_NEW_HW_PARAMS_API#undef ALSA_PCM_NEW_SW_PARAMS_API#include <sys/poll.h>#include <string.h> /* strlen() */#include <limits.h>#include <math.h>#include <pthread.h>#include <signal.h>#include <time.h>#include <sys/mman.h>#include <signal.h> /* For sig_atomic_t */#include "portaudio.h"#include "pa_util.h"#include "pa_unix_util.h"#include "pa_allocation.h"#include "pa_hostapi.h"#include "pa_stream.h"#include "pa_cpuload.h"#include "pa_process.h"#include "pa_linux_alsa.h"/* Check return value of ALSA function, and map it to PaError */#define ENSURE_(expr, code) \ do { \ if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( (code) == paUnanticipatedHostError && pthread_self() != callbackThread_ ) \ { \ PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \ } \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (code); \ goto error; \ } \ } while( 0 );#define ASSERT_CALL_(expr, success) \ aErr_ = (expr); \ assert( aErr_ == success );static int aErr_; /* Used with ENSURE_ */static pthread_t callbackThread_;typedef enum{ StreamDirection_In, StreamDirection_Out} StreamDirection;/* Threading utility struct */typedef struct PaAlsaThreading{ pthread_t watchdogThread; pthread_t callbackThread; int watchdogRunning; int rtSched; int rtPrio; int useWatchdog; unsigned long throttledSleepTime; volatile PaTime callbackTime; volatile PaTime callbackCpuTime; PaUtilCpuLoadMeasurer *cpuLoadMeasurer;} PaAlsaThreading;typedef struct{ PaSampleFormat hostSampleFormat; unsigned long framesPerBuffer; int numUserChannels, numHostChannels; int userInterleaved, hostInterleaved; snd_pcm_t *pcm; snd_pcm_uframes_t bufferSize; snd_pcm_format_t nativeFormat; unsigned int nfds; int ready; /* Marked ready from poll */ void **userBuffers; snd_pcm_uframes_t offset; StreamDirection streamDir; snd_pcm_channel_area_t *channelAreas; /* Needed for channel adaption */} PaAlsaStreamComponent;/* Implementation specific stream structure */typedef struct PaAlsaStream{ PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaAlsaThreading threading; unsigned long framesPerUserBuffer; int primeBuffers; int callbackMode; /* bool: are we running in callback mode? */ int pcmsSynced; /* Have we successfully synced pcms */ /* the callback thread uses these to poll the sound device(s), waiting * for data to be ready/available */ struct pollfd *pfds; int pollTimeout; /* Used in communication between threads */ volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */ volatile sig_atomic_t callbackAbort; /* Drop frames? */ volatile sig_atomic_t callbackStop; /* Signal a stop */ volatile sig_atomic_t isActive; /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */ pthread_mutex_t stateMtx; /* Used to synchronize access to stream state */ pthread_mutex_t startMtx; /* Used to synchronize stream start in callback mode */ pthread_cond_t startCond; /* Wait untill audio is started in callback thread */ int neverDropInput; PaTime underrun; PaTime overrun; PaAlsaStreamComponent capture, playback;}PaAlsaStream;/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */typedef struct PaAlsaHostApiRepresentation{ PaUtilHostApiRepresentation commonHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; PaHostApiIndex hostApiIndex;}PaAlsaHostApiRepresentation;typedef struct PaAlsaDeviceInfo{ PaDeviceInfo commonDeviceInfo; char *alsaName; int isPlug; int minInputChannels; int minOutputChannels;}PaAlsaDeviceInfo;/* Threading utilities */static void InitializeThreading( PaAlsaThreading *th, PaUtilCpuLoadMeasurer *clm ){ th->watchdogRunning = 0; th->rtSched = 0; th->callbackTime = 0; th->callbackCpuTime = 0; th->useWatchdog = 1; th->throttledSleepTime = 0; th->cpuLoadMeasurer = clm; th->rtPrio = (sched_get_priority_max( SCHED_FIFO ) - sched_get_priority_min( SCHED_FIFO )) / 2 + sched_get_priority_min( SCHED_FIFO );}static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitResult, PaError *watchdogExitResult ){ PaError result = paNoError; void *pret; if( exitResult ) *exitResult = paNoError; if( watchdogExitResult ) *watchdogExitResult = paNoError; if( th->watchdogRunning ) { pthread_cancel( th->watchdogThread ); ASSERT_CALL_( pthread_join( th->watchdogThread, &pret ), 0 ); if( pret && pret != PTHREAD_CANCELED ) { if( watchdogExitResult ) *watchdogExitResult = *(PaError *) pret; free( pret ); } } /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ /* TODO: Make join time out */ if( !wait ) pthread_cancel( th->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */ ASSERT_CALL_( pthread_join( th->callbackThread, &pret ), 0 ); if( pret && pret != PTHREAD_CANCELED ) { if( exitResult ) *exitResult = *(PaError *) pret; free( pret ); } return result;}static void OnWatchdogExit( void *userData ){ PaAlsaThreading *th = (PaAlsaThreading *) userData; struct sched_param spm = { 0 }; assert( th ); ASSERT_CALL_( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */ PA_DEBUG(( "Watchdog exiting\n" ));}static PaError BoostPriority( PaAlsaThreading *th ){ PaError result = paNoError; struct sched_param spm = { 0 }; spm.sched_priority = th->rtPrio; assert( th ); if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 ) { PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */ PA_DEBUG(( "Failed bumping priority\n" )); result = 0; } else result = 1; /* Success */error: return result;}static void *WatchdogFunc( void *userData ){ PaError result = paNoError, *pres = NULL; int err; PaAlsaThreading *th = (PaAlsaThreading *) userData; unsigned intervalMsec = 500; const PaTime maxSeconds = 3.; /* Max seconds between callbacks */ PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed; double cpuLoad, avgCpuLoad = 0.; int throttled = 0; assert( th ); pthread_cleanup_push( &OnWatchdogExit, th ); /* Execute OnWatchdogExit when exiting */ /* Boost priority of callback thread */ PA_ENSURE( result = BoostPriority( th ) ); if( !result ) { pthread_exit( NULL ); /* Boost failed, might as well exit */ } cpuTimeThen = th->callbackCpuTime; { int policy; struct sched_param spm = { 0 }; pthread_getschedparam( pthread_self(), &policy, &spm ); PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority )); } while( 1 ) { double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff; /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */ pthread_testcancel(); Pa_Sleep( intervalMsec ); pthread_testcancel(); if( PaUtil_GetTime() - th->callbackTime > maxSeconds ) { PA_DEBUG(( "Watchdog: Terminating callback thread\n" )); /* Tell thread to terminate */ err = pthread_kill( th->callbackThread, SIGKILL ); pthread_exit( NULL ); } PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) )); /* Check if we should throttle, or unthrottle :P */ cpuTimeNow = th->callbackCpuTime; cpuTimeElapsed = cpuTimeNow - cpuTimeThen; cpuTimeThen = cpuTimeNow; timeNow = PaUtil_GetTime(); timeElapsed = timeNow - timeThen; timeThen = timeNow; cpuLoad = cpuTimeElapsed / timeElapsed; avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1; /* if( throttled ) PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed )); */ if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 ) { static int policy; static struct sched_param spm = { 0 };
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?