Lines 6-11
Link Here
|
6 |
* |
6 |
* |
7 |
* Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> |
7 |
* Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> |
8 |
* Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no> |
8 |
* Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no> |
|
|
9 |
* Copyright (c) 2008 Kevin Kofler <kevin.kofler@chello.at> |
9 |
* |
10 |
* |
10 |
* Based on the Open Source API proposed by Ross Bencina |
11 |
* Based on the Open Source API proposed by Ross Bencina |
11 |
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk |
12 |
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk |
Lines 118-123
Link Here
|
118 |
unsigned long framesPerBuffer; |
119 |
unsigned long framesPerBuffer; |
119 |
int numUserChannels, numHostChannels; |
120 |
int numUserChannels, numHostChannels; |
120 |
int userInterleaved, hostInterleaved; |
121 |
int userInterleaved, hostInterleaved; |
|
|
122 |
int canMmap; |
123 |
void *nonMmapBuffer; |
121 |
PaDeviceIndex device; /* Keep the device index */ |
124 |
PaDeviceIndex device; /* Keep the device index */ |
122 |
|
125 |
|
123 |
snd_pcm_t *pcm; |
126 |
snd_pcm_t *pcm; |
Lines 321-327
Link Here
|
321 |
* and a suitable result returned. The device is closed before returning. |
324 |
* and a suitable result returned. The device is closed before returning. |
322 |
*/ |
325 |
*/ |
323 |
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking, |
326 |
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking, |
324 |
PaAlsaDeviceInfo* devInfo, int* canMmap ) |
327 |
PaAlsaDeviceInfo* devInfo ) |
325 |
{ |
328 |
{ |
326 |
PaError result = paNoError; |
329 |
PaError result = paNoError; |
327 |
snd_pcm_hw_params_t *hwParams; |
330 |
snd_pcm_hw_params_t *hwParams; |
Lines 354-362
Link Here
|
354 |
snd_pcm_hw_params_alloca( &hwParams ); |
357 |
snd_pcm_hw_params_alloca( &hwParams ); |
355 |
snd_pcm_hw_params_any( pcm, hwParams ); |
358 |
snd_pcm_hw_params_any( pcm, hwParams ); |
356 |
|
359 |
|
357 |
*canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 || |
|
|
358 |
snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0; |
359 |
|
360 |
if( defaultSr >= 0 ) |
360 |
if( defaultSr >= 0 ) |
361 |
{ |
361 |
{ |
362 |
/* Could be that the device opened in one mode supports samplerates that the other mode wont have, |
362 |
/* Could be that the device opened in one mode supports samplerates that the other mode wont have, |
Lines 566-572
Link Here
|
566 |
PaError result = 0; |
566 |
PaError result = 0; |
567 |
PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; |
567 |
PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; |
568 |
snd_pcm_t *pcm; |
568 |
snd_pcm_t *pcm; |
569 |
int canMmap = -1; |
|
|
570 |
PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; |
569 |
PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; |
571 |
|
570 |
|
572 |
/* Zero fields */ |
571 |
/* Zero fields */ |
Lines 580-587
Link Here
|
580 |
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) |
579 |
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) |
581 |
>= 0 ) |
580 |
>= 0 ) |
582 |
{ |
581 |
{ |
583 |
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo, |
582 |
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError ) |
584 |
&canMmap ) != paNoError ) |
|
|
585 |
{ |
583 |
{ |
586 |
/* Error */ |
584 |
/* Error */ |
587 |
PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName)); |
585 |
PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName)); |
Lines 594-601
Link Here
|
594 |
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) |
592 |
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) |
595 |
>= 0 ) |
593 |
>= 0 ) |
596 |
{ |
594 |
{ |
597 |
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo, |
595 |
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError ) |
598 |
&canMmap ) != paNoError ) |
|
|
599 |
{ |
596 |
{ |
600 |
/* Error */ |
597 |
/* Error */ |
601 |
PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName)); |
598 |
PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName)); |
Lines 603-614
Link Here
|
603 |
} |
600 |
} |
604 |
} |
601 |
} |
605 |
|
602 |
|
606 |
if( 0 == canMmap ) |
|
|
607 |
{ |
608 |
PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceName->alsaName)); |
609 |
goto end; |
610 |
} |
611 |
|
612 |
baseDeviceInfo->structVersion = 2; |
603 |
baseDeviceInfo->structVersion = 2; |
613 |
baseDeviceInfo->hostApi = alsaApi->hostApiIndex; |
604 |
baseDeviceInfo->hostApi = alsaApi->hostApiIndex; |
614 |
baseDeviceInfo->name = deviceName->name; |
605 |
baseDeviceInfo->name = deviceName->name; |
Lines 1197-1202
Link Here
|
1197 |
self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved); |
1188 |
self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved); |
1198 |
self->numUserChannels = params->channelCount; |
1189 |
self->numUserChannels = params->channelCount; |
1199 |
self->streamDir = streamDir; |
1190 |
self->streamDir = streamDir; |
|
|
1191 |
self->canMmap = 0; |
1192 |
self->nonMmapBuffer = NULL; |
1200 |
|
1193 |
|
1201 |
if( !callbackMode && !self->userInterleaved ) |
1194 |
if( !callbackMode && !self->userInterleaved ) |
1202 |
{ |
1195 |
{ |
Lines 1239-1244
Link Here
|
1239 |
|
1232 |
|
1240 |
PaError result = paNoError; |
1233 |
PaError result = paNoError; |
1241 |
snd_pcm_access_t accessMode, alternateAccessMode; |
1234 |
snd_pcm_access_t accessMode, alternateAccessMode; |
|
|
1235 |
snd_pcm_access_t rwAccessMode, alternateRwAccessMode; |
1242 |
int dir = 0; |
1236 |
int dir = 0; |
1243 |
snd_pcm_t *pcm = self->pcm; |
1237 |
snd_pcm_t *pcm = self->pcm; |
1244 |
double sr = *sampleRate; |
1238 |
double sr = *sampleRate; |
Lines 1258-1289
Link Here
|
1258 |
if( self->userInterleaved ) |
1252 |
if( self->userInterleaved ) |
1259 |
{ |
1253 |
{ |
1260 |
accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; |
1254 |
accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; |
|
|
1255 |
rwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED; |
1261 |
alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; |
1256 |
alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; |
|
|
1257 |
alternateRwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; |
1262 |
} |
1258 |
} |
1263 |
else |
1259 |
else |
1264 |
{ |
1260 |
{ |
1265 |
accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; |
1261 |
accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; |
|
|
1262 |
rwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; |
1266 |
alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; |
1263 |
alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; |
|
|
1264 |
alternateRwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED; |
1267 |
} |
1265 |
} |
1268 |
/* If requested access mode fails, try alternate mode */ |
1266 |
/* If requested access mode fails, try alternate mode */ |
|
|
1267 |
self->canMmap = 1; |
1269 |
if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) |
1268 |
if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) |
1270 |
{ |
1269 |
{ |
1271 |
int err = 0; |
1270 |
if( snd_pcm_hw_params_set_access( pcm, hwParams, rwAccessMode ) >= 0 ) |
1272 |
if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0) |
1271 |
self->canMmap = 0; |
|
|
1272 |
else |
1273 |
{ |
1273 |
{ |
1274 |
result = paUnanticipatedHostError; |
1274 |
if( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ) < 0 ) |
1275 |
if( -EINVAL == err ) |
|
|
1276 |
{ |
1275 |
{ |
1277 |
PaUtil_SetLastHostErrorInfo( paALSA, err, "PA ALSA requires that a device supports mmap access" ); |
1276 |
int err = 0; |
1278 |
} |
1277 |
if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateRwAccessMode )) >= 0) |
1279 |
else |
1278 |
self->canMmap = 0; |
1280 |
{ |
1279 |
else |
1281 |
PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) ); |
1280 |
{ |
|
|
1281 |
result = paUnanticipatedHostError; |
1282 |
PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) ); |
1283 |
goto error; |
1284 |
} |
1282 |
} |
1285 |
} |
1283 |
goto error; |
1286 |
/* Flip mode */ |
|
|
1287 |
self->hostInterleaved = !self->userInterleaved; |
1284 |
} |
1288 |
} |
1285 |
/* Flip mode */ |
|
|
1286 |
self->hostInterleaved = !self->userInterleaved; |
1287 |
} |
1289 |
} |
1288 |
|
1290 |
|
1289 |
ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); |
1291 |
ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); |
Lines 1361-1367
Link Here
|
1361 |
|
1363 |
|
1362 |
ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); |
1364 |
ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); |
1363 |
ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); |
1365 |
ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); |
1364 |
ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError ); |
1366 |
ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); |
1365 |
|
1367 |
|
1366 |
/* Set the parameters! */ |
1368 |
/* Set the parameters! */ |
1367 |
ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); |
1369 |
ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); |
Lines 1589-1594
Link Here
|
1589 |
} |
1591 |
} |
1590 |
} |
1592 |
} |
1591 |
|
1593 |
|
|
|
1594 |
/* non-mmap mode needs a reasonably-sized buffer or it'll stutter */ |
1595 |
/*if( !self->canMmap && framesPerHostBuffer < 2048 ) |
1596 |
framesPerHostBuffer = 2048; */ /* This above was commented out by David Henningsson, for Audacity - users need to be able to tweak latency themselves */ |
1597 |
|
1592 |
assert( framesPerHostBuffer > 0 ); |
1598 |
assert( framesPerHostBuffer > 0 ); |
1593 |
{ |
1599 |
{ |
1594 |
snd_pcm_uframes_t min = 0, max = 0; |
1600 |
snd_pcm_uframes_t min = 0, max = 0; |
Lines 1831-1837
Link Here
|
1831 |
PA_UNLESS( framesPerHostBuffer != 0, paInternalError ); |
1837 |
PA_UNLESS( framesPerHostBuffer != 0, paInternalError ); |
1832 |
self->maxFramesPerHostBuffer = framesPerHostBuffer; |
1838 |
self->maxFramesPerHostBuffer = framesPerHostBuffer; |
1833 |
|
1839 |
|
1834 |
if( !accurate ) |
1840 |
if( !self->playback.canMmap || !accurate ) |
1835 |
{ |
1841 |
{ |
1836 |
/* Don't know the exact size per host buffer */ |
1842 |
/* Don't know the exact size per host buffer */ |
1837 |
*hostBufferSizeMode = paUtilBoundedHostBufferSize; |
1843 |
*hostBufferSizeMode = paUtilBoundedHostBufferSize; |
Lines 2059-2067
Link Here
|
2059 |
{ |
2065 |
{ |
2060 |
/* Buffer isn't primed, so prepare and silence */ |
2066 |
/* Buffer isn't primed, so prepare and silence */ |
2061 |
ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); |
2067 |
ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); |
2062 |
SilenceBuffer( stream ); |
2068 |
if( stream->playback.canMmap ) |
|
|
2069 |
SilenceBuffer( stream ); |
2063 |
} |
2070 |
} |
2064 |
ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); |
2071 |
if( stream->playback.canMmap ) |
|
|
2072 |
ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); |
2065 |
} |
2073 |
} |
2066 |
else |
2074 |
else |
2067 |
ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); |
2075 |
ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); |
Lines 2390-2395
Link Here
|
2390 |
snd_pcm_status_t *st; |
2398 |
snd_pcm_status_t *st; |
2391 |
PaTime now = PaUtil_GetTime(); |
2399 |
PaTime now = PaUtil_GetTime(); |
2392 |
snd_timestamp_t t; |
2400 |
snd_timestamp_t t; |
|
|
2401 |
int errplayback = 0, errcapture = 0; |
2393 |
|
2402 |
|
2394 |
snd_pcm_status_alloca( &st ); |
2403 |
snd_pcm_status_alloca( &st ); |
2395 |
|
2404 |
|
Lines 2400-2405
Link Here
|
2400 |
{ |
2409 |
{ |
2401 |
snd_pcm_status_get_trigger_tstamp( st, &t ); |
2410 |
snd_pcm_status_get_trigger_tstamp( st, &t ); |
2402 |
self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); |
2411 |
self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); |
|
|
2412 |
errplayback = snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ); |
2403 |
} |
2413 |
} |
2404 |
} |
2414 |
} |
2405 |
if( self->capture.pcm ) |
2415 |
if( self->capture.pcm ) |
Lines 2409-2418
Link Here
|
2409 |
{ |
2419 |
{ |
2410 |
snd_pcm_status_get_trigger_tstamp( st, &t ); |
2420 |
snd_pcm_status_get_trigger_tstamp( st, &t ); |
2411 |
self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); |
2421 |
self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); |
|
|
2422 |
errcapture = snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ); |
2412 |
} |
2423 |
} |
2413 |
} |
2424 |
} |
2414 |
|
2425 |
|
2415 |
PA_ENSURE( AlsaRestart( self ) ); |
2426 |
if( errplayback || errcapture ) |
|
|
2427 |
PA_ENSURE( AlsaRestart( self ) ); |
2416 |
|
2428 |
|
2417 |
end: |
2429 |
end: |
2418 |
return result; |
2430 |
return result; |
Lines 2563-2569
Link Here
|
2563 |
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun ) |
2575 |
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun ) |
2564 |
{ |
2576 |
{ |
2565 |
PaError result = paNoError; |
2577 |
PaError result = paNoError; |
2566 |
int res; |
2578 |
int res = 0; |
2567 |
|
2579 |
|
2568 |
/* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed |
2580 |
/* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed |
2569 |
* afterwards |
2581 |
* afterwards |
Lines 2571-2577
Link Here
|
2571 |
if( !self->ready ) |
2583 |
if( !self->ready ) |
2572 |
goto end; |
2584 |
goto end; |
2573 |
|
2585 |
|
2574 |
res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); |
2586 |
if( !self->canMmap && StreamDirection_Out == self->streamDir ) |
|
|
2587 |
{ |
2588 |
/* Play sound */ |
2589 |
if( self->hostInterleaved ) |
2590 |
res = snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames ); |
2591 |
else |
2592 |
{ |
2593 |
void *bufs[self->numHostChannels]; |
2594 |
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); |
2595 |
unsigned char *buffer = self->nonMmapBuffer; |
2596 |
int i; |
2597 |
for( i = 0; i < self->numHostChannels; ++i ) |
2598 |
{ |
2599 |
bufs[i] = buffer; |
2600 |
buffer += bufsize; |
2601 |
} |
2602 |
res = snd_pcm_writen( self->pcm, bufs, numFrames ); |
2603 |
} |
2604 |
} |
2605 |
|
2606 |
if( self->canMmap ) |
2607 |
res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); |
2608 |
else |
2609 |
{ |
2610 |
free( self->nonMmapBuffer ); |
2611 |
self->nonMmapBuffer = NULL; |
2612 |
} |
2613 |
|
2575 |
if( res == -EPIPE || res == -ESTRPIPE ) |
2614 |
if( res == -EPIPE || res == -ESTRPIPE ) |
2576 |
{ |
2615 |
{ |
2577 |
*xrun = 1; |
2616 |
*xrun = 1; |
Lines 2611-2617
Link Here
|
2611 |
if( self->hostInterleaved ) |
2650 |
if( self->hostInterleaved ) |
2612 |
{ |
2651 |
{ |
2613 |
int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); |
2652 |
int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); |
2614 |
unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset ); |
2653 |
unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer; |
2615 |
|
2654 |
|
2616 |
/* Start after the last user channel */ |
2655 |
/* Start after the last user channel */ |
2617 |
p = buffer + self->numUserChannels * swidth; |
2656 |
p = buffer + self->numUserChannels * swidth; |
Lines 2991-3003
Link Here
|
2991 |
goto end; |
3030 |
goto end; |
2992 |
} |
3031 |
} |
2993 |
|
3032 |
|
2994 |
ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); |
3033 |
if( self->canMmap ) |
|
|
3034 |
{ |
3035 |
ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); |
3036 |
/* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */ |
3037 |
self->channelAreas = (snd_pcm_channel_area_t *)areas; |
3038 |
} |
3039 |
else |
3040 |
{ |
3041 |
free( self->nonMmapBuffer ); |
3042 |
self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) ); |
3043 |
} |
2995 |
|
3044 |
|
2996 |
if( self->hostInterleaved ) |
3045 |
if( self->hostInterleaved ) |
2997 |
{ |
3046 |
{ |
2998 |
int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); |
3047 |
int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); |
2999 |
|
3048 |
|
3000 |
p = buffer = ExtractAddress( areas, self->offset ); |
3049 |
p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer; |
3001 |
for( i = 0; i < self->numUserChannels; ++i ) |
3050 |
for( i = 0; i < self->numUserChannels; ++i ) |
3002 |
{ |
3051 |
{ |
3003 |
/* We're setting the channels up to userChannels, but the stride will be hostChannels samples */ |
3052 |
/* We're setting the channels up to userChannels, but the stride will be hostChannels samples */ |
Lines 3007-3022
Link Here
|
3007 |
} |
3056 |
} |
3008 |
else |
3057 |
else |
3009 |
{ |
3058 |
{ |
3010 |
for( i = 0; i < self->numUserChannels; ++i ) |
3059 |
if( self->canMmap ) |
|
|
3060 |
for( i = 0; i < self->numUserChannels; ++i ) |
3061 |
{ |
3062 |
area = areas + i; |
3063 |
buffer = ExtractAddress( area, self->offset ); |
3064 |
setChannel( bp, i, buffer, 1 ); |
3065 |
} |
3066 |
else |
3011 |
{ |
3067 |
{ |
3012 |
area = areas + i; |
3068 |
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); |
3013 |
buffer = ExtractAddress( area, self->offset ); |
3069 |
buffer = self->nonMmapBuffer; |
3014 |
setChannel( bp, i, buffer, 1 ); |
3070 |
for( i = 0; i < self->numUserChannels; ++i ) |
|
|
3071 |
{ |
3072 |
setChannel( bp, i, buffer, 1 ); |
3073 |
buffer += bufsize; |
3074 |
} |
3015 |
} |
3075 |
} |
3016 |
} |
3076 |
} |
3017 |
|
3077 |
|
3018 |
/* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */ |
3078 |
if( !self->canMmap && StreamDirection_In == self->streamDir ) |
3019 |
self->channelAreas = (snd_pcm_channel_area_t *)areas; |
3079 |
{ |
|
|
3080 |
/* Read sound */ |
3081 |
int res; |
3082 |
if( self->hostInterleaved ) |
3083 |
res = snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames ); |
3084 |
else |
3085 |
{ |
3086 |
void *bufs[self->numHostChannels]; |
3087 |
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); |
3088 |
unsigned char *buffer = self->nonMmapBuffer; |
3089 |
int i; |
3090 |
for( i = 0; i < self->numHostChannels; ++i ) |
3091 |
{ |
3092 |
bufs[i] = buffer; |
3093 |
buffer += bufsize; |
3094 |
} |
3095 |
res = snd_pcm_readn( self->pcm, bufs, *numFrames ); |
3096 |
} |
3097 |
if( res == -EPIPE || res == -ESTRPIPE ) |
3098 |
{ |
3099 |
*xrun = 1; |
3100 |
*numFrames = 0; |
3101 |
free( self->nonMmapBuffer ); |
3102 |
self->nonMmapBuffer = NULL; |
3103 |
} |
3104 |
} |
3020 |
|
3105 |
|
3021 |
end: |
3106 |
end: |
3022 |
error: |
3107 |
error: |