diff options
author | Guenter Geiger <ggeiger@users.sourceforge.net> | 2004-02-02 12:18:59 +0000 |
---|---|---|
committer | Guenter Geiger <ggeiger@users.sourceforge.net> | 2004-02-02 12:18:59 +0000 |
commit | 2e416ee0095f1bf608f849f156d564e0f45fb8ab (patch) | |
tree | 9e4881e81953b434b91dbd35218d78f05b27e82e /pd/portaudio/pa_linux_alsa | |
parent | ae6b5d89ea93b95c2990895077cf5e8f0bba9ad9 (diff) |
merged in version_0_37_1test6
svn path=/trunk/; revision=1305
Diffstat (limited to 'pd/portaudio/pa_linux_alsa')
-rw-r--r-- | pd/portaudio/pa_linux_alsa/blocking_calls.c | 61 | ||||
-rw-r--r-- | pd/portaudio/pa_linux_alsa/callback_thread.c | 374 | ||||
-rw-r--r-- | pd/portaudio/pa_linux_alsa/pa_linux_alsa.c | 989 | ||||
-rw-r--r-- | pd/portaudio/pa_linux_alsa/pa_linux_alsa.h | 45 |
4 files changed, 0 insertions, 1469 deletions
diff --git a/pd/portaudio/pa_linux_alsa/blocking_calls.c b/pd/portaudio/pa_linux_alsa/blocking_calls.c deleted file mode 100644 index 6304b117..00000000 --- a/pd/portaudio/pa_linux_alsa/blocking_calls.c +++ /dev/null @@ -1,61 +0,0 @@ - -#include "pa_stream.h" - -#include "pa_linux_alsa.h" - -PaError ReadStream( PaStream* s, - void *buffer, - unsigned long frames ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - /* TODO: handle failure, xruns */ - - if( stream->capture_interleaved ) - { - snd_pcm_mmap_readi( stream->pcm_capture, buffer, frames ); - } - else - { - snd_pcm_mmap_readn( stream->pcm_capture, (void**)buffer, frames ); - } - - return paNoError; -} - - -PaError WriteStream( PaStream* s, - void *buffer, - unsigned long frames ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - if( stream->playback_interleaved ) - { - snd_pcm_mmap_writei( stream->pcm_playback, buffer, frames ); - } - else - { - snd_pcm_mmap_writen( stream->pcm_playback, (void**)buffer, frames ); - } - - return paNoError; -} - - -unsigned long GetStreamReadAvailable( PaStream* s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - return snd_pcm_avail_update( stream->pcm_capture ); -} - - -unsigned long GetStreamWriteAvailable( PaStream* s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - return snd_pcm_avail_update( stream->pcm_playback ); -} - - diff --git a/pd/portaudio/pa_linux_alsa/callback_thread.c b/pd/portaudio/pa_linux_alsa/callback_thread.c deleted file mode 100644 index 483557b6..00000000 --- a/pd/portaudio/pa_linux_alsa/callback_thread.c +++ /dev/null @@ -1,374 +0,0 @@ - -#include <sys/poll.h> -#include <limits.h> -#include <math.h> /* abs() */ - -#include <alsa/asoundlib.h> - -#include "pa_linux_alsa.h" - -#define MIN(x,y) ( (x) < (y) ? (x) : (y) ) - -static int wait( PaAlsaStream *stream ) -{ - int need_capture; - int need_playback; - int capture_avail = INT_MAX; - int playback_avail = INT_MAX; - int common_avail; - - if( stream->pcm_capture ) - need_capture = 1; - else - need_capture = 0; - - if( stream->pcm_playback ) - need_playback = 1; - else - need_playback = 0; - - while( need_capture || need_playback ) - { - int playback_pfd_offset=0; - int total_fds = 0; - - /* if the main thread has requested that we stop, do so now */ - pthread_testcancel(); - - /*printf("still polling...\n"); - if( need_capture ) - printf("need capture.\n"); - if( need_playback ) - printf("need playback.\n"); */ - - /* get the fds, packing all applicable fds into a single array, - * so we can check them all with a single poll() call */ - - if( need_capture ) - { - snd_pcm_poll_descriptors( stream->pcm_capture, stream->pfds, - stream->capture_nfds ); - total_fds += stream->capture_nfds; - } - - if( need_playback ) - { - playback_pfd_offset = total_fds; - snd_pcm_poll_descriptors( stream->pcm_playback, - stream->pfds + playback_pfd_offset, - stream->playback_nfds ); - total_fds += stream->playback_nfds; - } - - /* now poll on the combination of playback and capture fds. - * TODO: handle interrupt and/or failure */ - poll( stream->pfds, total_fds, 1000 ); - - /* check the return status of our pfds */ - if( need_capture ) - { - short revents; - snd_pcm_poll_descriptors_revents( stream->pcm_capture, stream->pfds, - stream->capture_nfds, &revents ); - if( revents == POLLIN ) - need_capture = 0; - } - - if( need_playback ) - { - short revents; - snd_pcm_poll_descriptors_revents( stream->pcm_playback, - stream->pfds + playback_pfd_offset, - stream->playback_nfds, &revents ); - //if( revents & POLLOUT ) - //if( revents & POLLERR ) - // printf("polling error!"); - if( revents == POLLOUT ) - need_playback = 0; - } - } - - /* we have now established that there are buffers ready to be - * operated on. Now determine how many frames are available. */ - if( stream->pcm_capture ) - capture_avail = snd_pcm_avail_update( stream->pcm_capture ); - - if( stream->pcm_playback ) - playback_avail = snd_pcm_avail_update( stream->pcm_playback ); - - common_avail = MIN(capture_avail, playback_avail); - common_avail -= common_avail % stream->frames_per_period; - - return common_avail; -} - -static int setup_buffers( PaAlsaStream *stream, int frames_avail ) -{ - int i; - int capture_frames_avail = INT_MAX; - int playback_frames_avail = INT_MAX; - int common_frames_avail; - - if( stream->pcm_capture ) - { - const snd_pcm_channel_area_t *capture_areas; - const snd_pcm_channel_area_t *area; - snd_pcm_uframes_t frames = frames_avail; - - /* I do not understand this code fragment yet, it is copied out of the - * alsa-devel archives... */ - snd_pcm_mmap_begin( stream->pcm_capture, &capture_areas, - &stream->capture_offset, &frames); - - if( stream->capture_interleaved ) - { - void *interleaved_capture_buffer; - area = &capture_areas[0]; - interleaved_capture_buffer = area->addr + - (area->first + area->step * stream->capture_offset) / 8; - PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, - 0, /* starting at channel 0 */ - interleaved_capture_buffer, - 0 /* default numInputChannels */ - ); - } - else - { - /* noninterleaved */ - void *noninterleaved_capture_buffers[1000]; - for( i = 0; i < stream->capture_channels; i++ ) - { - area = &capture_areas[i]; - noninterleaved_capture_buffers[i] = area->addr + - (area->first + area->step * stream->capture_offset) / 8; - PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor, - i, - noninterleaved_capture_buffers[i]); - } - } - - capture_frames_avail = frames; - } - - if( stream->pcm_playback ) - { - const snd_pcm_channel_area_t *playback_areas; - const snd_pcm_channel_area_t *area; - snd_pcm_uframes_t frames = frames_avail; - - /* I do not understand this code fragment yet, it is copied out of the - * alsa-devel archives... */ - snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas, - &stream->playback_offset, &frames); - - if( stream->playback_interleaved ) - { - void *interleaved_playback_buffer; - area = &playback_areas[0]; - interleaved_playback_buffer = area->addr + - (area->first + area->step * stream->playback_offset) / 8; - PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, - 0, /* starting at channel 0 */ - interleaved_playback_buffer, - 0 /* default numInputChannels */ - ); - } - else - { - /* noninterleaved */ - void *noninterleaved_playback_buffers[1000]; - for( i = 0; i < stream->playback_channels; i++ ) - { - area = &playback_areas[i]; - noninterleaved_playback_buffers[i] = area->addr + - (area->first + area->step * stream->playback_offset) / 8; - PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor, - i, - noninterleaved_playback_buffers[i]); - } - } - - playback_frames_avail = frames; - } - - - common_frames_avail = MIN(capture_frames_avail, playback_frames_avail); - common_frames_avail -= common_frames_avail % stream->frames_per_period; - //printf( "%d capture frames available\n", capture_frames_avail ); - //printf( "%d frames playback available\n", playback_frames_avail ); - //printf( "%d frames available\n", common_frames_avail ); - - if( stream->pcm_capture ) - PaUtil_SetInputFrameCount( &stream->bufferProcessor, common_frames_avail ); - - if( stream->pcm_playback ) - PaUtil_SetOutputFrameCount( &stream->bufferProcessor, common_frames_avail ); - - return common_frames_avail; -} - -void *CallbackThread( void *userData ) -{ - PaAlsaStream *stream = (PaAlsaStream*)userData; - - if( stream->pcm_capture ) - snd_pcm_start( stream->pcm_capture ); - if( stream->pcm_playback ) - snd_pcm_start( stream->pcm_playback ); - - while(1) - { - int frames_avail; - int frames_got; - - PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ - int callbackResult; - int framesProcessed; - - pthread_testcancel(); - { - /* calculate time info */ - snd_timestamp_t capture_timestamp; - snd_timestamp_t playback_timestamp; - snd_pcm_status_t *capture_status; - snd_pcm_status_t *playback_status; - snd_pcm_status_alloca( &capture_status ); - snd_pcm_status_alloca( &playback_status ); - - if( stream->pcm_capture ) - { - snd_pcm_status( stream->pcm_capture, capture_status ); - snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); - } - if( stream->pcm_playback ) - { - snd_pcm_status( stream->pcm_playback, playback_status ); - snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); - } - - /* Hmm, we potentially have both a playback and a capture timestamp. - * Hopefully they are the same... */ - if( stream->pcm_capture && stream->pcm_playback ) - { - float capture_time = capture_timestamp.tv_sec + - ((float)capture_timestamp.tv_usec/1000000); - float playback_time= playback_timestamp.tv_sec + - ((float)playback_timestamp.tv_usec/1000000); - if( fabsf(capture_time-playback_time) > 0.01 ) - printf("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time)); - timeInfo.currentTime = capture_time; - } - else if( stream->pcm_playback ) - { - timeInfo.currentTime = playback_timestamp.tv_sec + - ((float)playback_timestamp.tv_usec/1000000); - } - else - { - timeInfo.currentTime = capture_timestamp.tv_sec + - ((float)capture_timestamp.tv_usec/1000000); - } - - if( stream->pcm_capture ) - { - snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status ); - timeInfo.inputBufferAdcTime = timeInfo.currentTime - - (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate; - } - - if( stream->pcm_playback ) - { - snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status ); - timeInfo.outputBufferDacTime = timeInfo.currentTime + - (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate; - } - } - - - /* - IMPLEMENT ME: - - handle buffer slips - */ - - /* - depending on whether the host buffers are interleaved, non-interleaved - or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(), - PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here. - */ - - frames_avail = wait( stream ); - //printf( "%d frames available\n", frames_avail ); - - /* Now we know the soundcard is ready to produce/receive at least - * one period. We just need to get the buffers for the client - * to read/write. */ - PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo ); - - frames_got = setup_buffers( stream, frames_avail ); - - if( frames_avail == frames_got ) - ;//printf("good, they were both %d\n", frames_avail ); - else - printf("damn, they were different: avail: %d, got: %d\n", frames_avail, frames_got ); - - /* this calls the callback */ - - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - - framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, - &callbackResult ); - - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - - /* inform ALSA how many frames we wrote */ - - if( stream->pcm_capture ) - snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_avail ); - - if( stream->pcm_playback ) - snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_avail ); - - - /* - If you need to byte swap outputBuffer, you can do it here using - routines in pa_byteswappers.h - */ - - if( callbackResult == paContinue ) - { - /* nothing special to do */ - } - else if( callbackResult == paAbort ) - { - stream->callback_finished = 1; - - if( stream->pcm_capture ) - { - snd_pcm_drop( stream->pcm_capture ); - } - - if( stream->pcm_playback ) - { - snd_pcm_drop( stream->pcm_playback ); - } - pthread_exit(NULL); - } - else - { - stream->callback_finished = 1; - - if( stream->pcm_capture ) - { - snd_pcm_drain( stream->pcm_capture ); - } - - if( stream->pcm_playback ) - { - snd_pcm_drain( stream->pcm_playback ); - } - pthread_exit(NULL); - } - - } -} - diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c deleted file mode 100644 index 9582b5b8..00000000 --- a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * $Id: pa_linux_alsa.c,v 1.1.2.3 2003/02/01 21:55:03 joshua Exp $ - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * ALSA implementation by Joshua Haberman - * - * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> - * - * 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. - */ - -#include <sys/poll.h> -#include <pthread.h> - -#include <string.h> /* strlen() */ -#include <limits.h> - -#include <alsa/asoundlib.h> - -#include "portaudio.h" -#include "pa_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" - -/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */ - -typedef struct -{ - PaUtilHostApiRepresentation commonHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; - - PaUtilAllocationGroup *allocations; - - PaHostApiIndex hostApiIndex; -} -PaAlsaHostApiRepresentation; - - -/* prototypes for functions declared in this file */ - -PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ); -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *callback, - void *userData ); -static PaError CloseStream( PaStream* stream ); -static PaError StartStream( PaStream *stream ); -static PaError StopStream( PaStream *stream ); -static PaError AbortStream( PaStream *stream ); -static PaError IsStreamStopped( PaStream *s ); -static PaError IsStreamActive( PaStream *stream ); -static PaTime GetStreamTime( PaStream *stream ); -static double GetStreamCpuLoad( PaStream* stream ); -static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi ); - -/* blocking calls are in blocking_calls.c */ -extern PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); -extern PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames ); -extern signed long GetStreamReadAvailable( PaStream* stream ); -extern signed long GetStreamWriteAvailable( PaStream* stream ); - -/* all callback-related functions are in callback_thread.c */ -extern void *CallbackThread( void *userData ); - - -PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) -{ - PaError result = paNoError; - int i, deviceCount; - PaAlsaHostApiRepresentation *skeletonHostApi; - - skeletonHostApi = (PaAlsaHostApiRepresentation*) - PaUtil_AllocateMemory( sizeof(PaAlsaHostApiRepresentation) ); - if( !skeletonHostApi ) - { - result = paInsufficientMemory; - goto error; - } - - skeletonHostApi->allocations = PaUtil_CreateAllocationGroup(); - if( !skeletonHostApi->allocations ) - { - result = paInsufficientMemory; - goto error; - } - - skeletonHostApi->hostApiIndex = hostApiIndex; - *hostApi = (PaUtilHostApiRepresentation*)skeletonHostApi; - (*hostApi)->info.structVersion = 1; - (*hostApi)->info.type = paALSA; - (*hostApi)->info.name = "ALSA implementation"; - - BuildDeviceList( skeletonHostApi ); - - (*hostApi)->Terminate = Terminate; - (*hostApi)->OpenStream = OpenStream; - - PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, - CloseStream, StartStream, - StopStream, AbortStream, - IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, - PaUtil_DummyGetAvailable, - PaUtil_DummyGetAvailable ); - - PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, - CloseStream, StartStream, - StopStream, AbortStream, - IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - ReadStream, WriteStream, - GetStreamReadAvailable, - GetStreamWriteAvailable ); - - return result; - -error: - if( skeletonHostApi ) - { - if( skeletonHostApi->allocations ) - { - PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); - PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); - } - - PaUtil_FreeMemory( skeletonHostApi ); - } - return result; -} - -static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) -{ - PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep; - PaDeviceInfo *deviceInfoArray; - int deviceCount = 0; - int card_idx; - int device_idx; - snd_ctl_t *ctl; - snd_ctl_card_info_t *card_info; - - /* count the devices by enumerating all the card numbers */ - - /* snd_card_next() modifies the integer passed to it to be: - * the index of the first card if the parameter is -1 - * the index of the next card if the parameter is the index of a card - * -1 if there are no more cards - * - * The function itself returns 0 if it succeeded. */ - card_idx = -1; - while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 ) - { - deviceCount++; - } - - /* allocate deviceInfo memory based on the number of devices */ - - commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - alsaApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); - if( !commonApi->deviceInfos ) - { - return paInsufficientMemory; - } - - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( - alsaApi->allocations, sizeof(PaDeviceInfo) * deviceCount ); - if( !deviceInfoArray ) - { - return paInsufficientMemory; - } - - /* now loop over the list of devices again, filling in the deviceInfo for each */ - card_idx = -1; - device_idx = 0; - while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 ) - { - PaDeviceInfo *deviceInfo = &deviceInfoArray[device_idx]; - char *deviceName; - char alsaDeviceName[50]; - const char *cardName; - - commonApi->deviceInfos[device_idx++] = deviceInfo; - - deviceInfo->structVersion = 2; - deviceInfo->hostApi = alsaApi->hostApiIndex; - - sprintf( alsaDeviceName, "hw:%d", card_idx ); - snd_ctl_open( &ctl, alsaDeviceName, 0 ); - snd_ctl_card_info_malloc( &card_info ); - snd_ctl_card_info( ctl, card_info ); - cardName = snd_ctl_card_info_get_id( card_info ); - - deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, - strlen(cardName) + 1 ); - if( !deviceName ) - { - return paInsufficientMemory; - } - strcpy( deviceName, cardName ); - deviceInfo->name = deviceName; - - snd_ctl_card_info_free( card_info ); - - /* to determine max. channels, we must open the device and query the - * hardware parameter configuration space */ - { - snd_pcm_t *pcm_handle; - snd_pcm_hw_params_t *hw_params; - int dir; - - snd_pcm_hw_params_malloc( &hw_params ); - - /* get max channels for capture */ - - if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 ) - { - deviceInfo->maxInputChannels = 0; - } - else - { - snd_pcm_hw_params_any( pcm_handle, hw_params ); - deviceInfo->maxInputChannels = snd_pcm_hw_params_get_channels_max( hw_params ); - /* TODO: I'm not really sure what to do here */ - //deviceInfo->defaultLowInputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir ); - //deviceInfo->defaultHighInputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir ); - deviceInfo->defaultLowInputLatency = 128. / 44100; - deviceInfo->defaultHighInputLatency = 16384. / 44100; - snd_pcm_close( pcm_handle ); - } - - /* get max channels for playback */ - if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 ) - { - deviceInfo->maxOutputChannels = 0; - } - else - { - snd_pcm_hw_params_any( pcm_handle, hw_params ); - deviceInfo->maxOutputChannels = snd_pcm_hw_params_get_channels_max( hw_params ); - /* TODO: I'm not really sure what to do here */ - //deviceInfo->defaultLowOutputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir ); - //deviceInfo->defaultHighOutputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir ); - deviceInfo->defaultLowOutputLatency = 128. / 44100; - deviceInfo->defaultHighOutputLatency = 16384. / 44100; - snd_pcm_close( pcm_handle ); - } - - snd_pcm_hw_params_free( hw_params ); - } - - deviceInfo->defaultSampleRate = 44100.; /* IMPLEMENT ME */ - } - - commonApi->info.deviceCount = deviceCount; - commonApi->info.defaultInputDevice = 0; - commonApi->info.defaultOutputDevice = 0; - - return paNoError; -} - - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) -{ - PaAlsaHostApiRepresentation *skeletonHostApi; - skeletonHostApi = (PaAlsaHostApiRepresentation*)hostApi; - - /* - IMPLEMENT ME: - - clean up any resourced not handled by the allocation group - */ - - if( skeletonHostApi->allocations ) - { - PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); - PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); - } - - PaUtil_FreeMemory( skeletonHostApi ); -} - - -/* Given an open stream, what sample formats are available? */ - -static PaSampleFormat GetAvailableFormats( snd_pcm_t *stream ) -{ - PaSampleFormat available = 0; - snd_pcm_hw_params_t *hw_params; - snd_pcm_hw_params_alloca( &hw_params ); - - snd_pcm_hw_params_any( stream, hw_params ); - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_FLOAT ) == 0) - available |= paFloat32; - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S16 ) == 0) - available |= paInt16; - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S24 ) == 0) - available |= paInt24; - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S32 ) == 0) - available |= paInt32; - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S8 ) == 0) - available |= paInt8; - - if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_U8 ) == 0) - available |= paUInt8; - - return available; -} - -/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ - -static PaError ConfigureStream( snd_pcm_t *stream, int channels, - int interleaved, unsigned long rate, - PaSampleFormat pa_format, int framesPerBuffer ) -{ -#define ENSURE(functioncall) \ - if( (functioncall) < 0 ) { \ - printf("Error executing ALSA call, line %d\n", __LINE__); \ - return 1; \ - } \ - else { \ - printf("ALSA call at line %d succeeded\n", __LINE__ ); \ - } - - snd_pcm_access_t access_mode; - snd_pcm_format_t alsa_format; - - /* configuration consists of setting all of ALSA's parameters. - * These parameters come in two flavors: hardware parameters - * and software paramters. Hardware parameters will affect - * the way the device is initialized, software parameters - * affect the way ALSA interacts with me, the user-level client. */ - - snd_pcm_hw_params_t *hw_params; - snd_pcm_sw_params_t *sw_params; - - snd_pcm_hw_params_alloca( &hw_params ); - - /* ... fill up the configuration space with all possibile - * combinations of parameters this device will accept */ - ENSURE( snd_pcm_hw_params_any( stream, hw_params ) ); - - if( interleaved ) - access_mode = SND_PCM_ACCESS_MMAP_INTERLEAVED; - else - access_mode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; - - ENSURE( snd_pcm_hw_params_set_access( stream, hw_params, access_mode ) ); - - /* set the format based on what the user selected */ - switch( pa_format ) - { - case paFloat32: - alsa_format = SND_PCM_FORMAT_FLOAT; - break; - - case paInt16: - alsa_format = SND_PCM_FORMAT_S16; - break; - - case paInt24: - alsa_format = SND_PCM_FORMAT_S24; - break; - - case paInt32: - alsa_format = SND_PCM_FORMAT_S32; - break; - - case paInt8: - alsa_format = SND_PCM_FORMAT_S8; - break; - - case paUInt8: - alsa_format = SND_PCM_FORMAT_U8; - break; - - default: - printf("Unknown PortAudio format %d\n", (int)pa_format ); - return 1; - } - //printf("PortAudio format: %d\n", pa_format); - printf("ALSA format: %d\n", alsa_format); - ENSURE( snd_pcm_hw_params_set_format( stream, hw_params, alsa_format ) ); - - /* ... set the sample rate */ - ENSURE( snd_pcm_hw_params_set_rate( stream, hw_params, rate, 0 ) ); - - /* ... set the number of channels */ - ENSURE( snd_pcm_hw_params_set_channels( stream, hw_params, channels ) ); - - /* ... set the number of periods to 2, which is essentially double buffering. - * this makes the latency the number of samples per buffer, which is the best - * it can be */ - ENSURE( snd_pcm_hw_params_set_periods ( stream, hw_params, 2, 0 ) ); - - /* ... set the period size, which is essentially the hardware buffer size */ - if( framesPerBuffer != 0 ) - { - ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params, - framesPerBuffer, 0 ) ); - } - else - { - ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params, - 2048, 0 ) ); - } - - - /* Set the parameters! */ - ENSURE( snd_pcm_hw_params( stream, hw_params ) ); - - return 0; -#undef ENSURE -} - -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *callback, - void *userData ) -{ - PaError result = paNoError; - PaAlsaHostApiRepresentation *skeletonHostApi = - (PaAlsaHostApiRepresentation*)hostApi; - PaAlsaStream *stream = 0; - PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0; - int numInputChannels, numOutputChannels; - PaSampleFormat inputSampleFormat=0, outputSampleFormat=0; - unsigned long framesPerHostBuffer = framesPerBuffer; - - if( framesPerHostBuffer == paFramesPerBufferUnspecified ) - { - // TODO: have some reason - framesPerHostBuffer = 2048; - } - - if( inputParameters ) - { - numInputChannels = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification. - [JH] this could be supported in the future, to allow ALSA device strings - like hw:0 */ - if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that input device can support numInputChannels */ - if( numInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) - return paInvalidChannelCount; - - /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - } - else - { - numInputChannels = 0; - } - - if( outputParameters ) - { - numOutputChannels = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification - [JH] this could be supported in the future, to allow ALSA device strings - like hw:0 */ - - if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that output device can support numInputChannels */ - if( numOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) - return paInvalidChannelCount; - - /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - } - else - { - numOutputChannels = 0; - } - - /* validate platform specific flags */ - if( (streamFlags & paPlatformSpecificFlags) != 0 ) - return paInvalidFlag; /* unexpected platform specific flag */ - - /* allocate and do basic initialization of the stream structure */ - - stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ); - if( !stream ) - { - printf("memory point 2\n"); - result = paInsufficientMemory; - goto error; - } - - stream->pcm_capture = NULL; - stream->pcm_playback = NULL; - stream->callback_mode = (callback != 0); - stream->callback_finished = 0; - - if( callback ) - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &skeletonHostApi->callbackStreamInterface, - callback, userData ); - } - else - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &skeletonHostApi->blockingStreamInterface, - callback, userData ); - } - - - stream->streamRepresentation.streamInfo.inputLatency = framesPerHostBuffer; - stream->streamRepresentation.streamInfo.outputLatency = framesPerHostBuffer; - stream->streamRepresentation.streamInfo.sampleRate = sampleRate; - - PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); - - /* open the devices now, so we can obtain info about the available formats */ - - if( numInputChannels > 0 ) - { - char inputDeviceName[50]; - - sprintf( inputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[inputParameters->device]->name ); - if( snd_pcm_open( &stream->pcm_capture, inputDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 ) - { - result = paBadIODeviceCombination; - goto error; - } - hostInputSampleFormat = - PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_capture), - inputSampleFormat ); - } - - if( numOutputChannels > 0 ) - { - char outputDeviceName[50]; - - sprintf( outputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[outputParameters->device]->name ); - if( snd_pcm_open( &stream->pcm_playback, outputDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 ) - { - result = paBadIODeviceCombination; - goto error; - } - hostOutputSampleFormat = - PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_playback), - outputSampleFormat ); - stream->playback_hostsampleformat = hostOutputSampleFormat; - } - - - - result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - numInputChannels, inputSampleFormat, hostInputSampleFormat, - numOutputChannels, outputSampleFormat, hostOutputSampleFormat, - sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer, - paUtilFixedHostBufferSize, callback, userData ); - if( result != paNoError ) - goto error; - - /* configure the streams */ - - if( numInputChannels > 0 ) - { - int interleaved; - PaSampleFormat plain_format = hostInputSampleFormat & ~paNonInterleaved; - - if( inputSampleFormat & paNonInterleaved ) - interleaved = 0; - else - interleaved = 1; - - if( ConfigureStream( stream->pcm_capture, numInputChannels, interleaved, - sampleRate, plain_format, framesPerHostBuffer ) != 0 ) - { - result = paBadIODeviceCombination; - goto error; - } - - stream->capture_interleaved = interleaved; - } - - if( numOutputChannels > 0 ) - { - int interleaved; - PaSampleFormat plain_format = hostOutputSampleFormat & ~paNonInterleaved; - - if( outputSampleFormat & paNonInterleaved ) - interleaved = 0; - else - interleaved = 1; - - if( ConfigureStream( stream->pcm_playback, numOutputChannels, interleaved, - sampleRate, plain_format, framesPerHostBuffer ) != 0 ) - { - result = paBadIODeviceCombination; - goto error; - } - - stream->playback_interleaved = interleaved; - } - - stream->capture_nfds = 0; - stream->playback_nfds = 0; - - if( stream->pcm_capture ) - stream->capture_nfds = snd_pcm_poll_descriptors_count( stream->pcm_capture ); - - if( stream->pcm_playback ) - stream->playback_nfds = snd_pcm_poll_descriptors_count( stream->pcm_playback ); - - /* TODO: free this properly */ - printf("trying to allocate %d bytes of memory\n", (stream->capture_nfds + stream->playback_nfds + 1) * sizeof(struct pollfd) ); - stream->pfds = (struct pollfd*)PaUtil_AllocateMemory( (stream->capture_nfds + - stream->playback_nfds + 1) * - sizeof(struct pollfd) ); - if( !stream->pfds ) - { - printf("bad memory point 1\n"); - result = paInsufficientMemory; - goto error; - } - - stream->frames_per_period = framesPerHostBuffer; - stream->capture_channels = numInputChannels; - stream->playback_channels = numOutputChannels; - - *s = (PaStream*)stream; - - return result; - -error: - if( stream ) - PaUtil_FreeMemory( stream ); - - return result; -} - - -/* - When CloseStream() is called, the multi-api layer ensures that - the stream has already been stopped or aborted. -*/ -static PaError CloseStream( PaStream* s ) -{ - PaError result = paNoError; - PaAlsaStream *stream = (PaAlsaStream*)s; - - if( stream->pcm_capture ) - { - snd_pcm_close( stream->pcm_capture ); - } - - if( stream->pcm_playback ) - { - snd_pcm_close( stream->pcm_playback ); - } - - PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); - PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); - PaUtil_FreeMemory( stream ); - - return result; -} - - -static PaError StartStream( PaStream *s ) -{ - PaError result = paNoError; - PaAlsaStream *stream = (PaAlsaStream*)s; - - /* TODO: support errorText */ -#define ENSURE(x) \ - { \ - int error_ret; \ - error_ret = (x); \ - if( error_ret != 0 ) { \ - PaHostErrorInfo err; \ - err.errorCode = error_ret; \ - err.hostApiType = paALSA; \ - printf("call at %d failed\n", __LINE__); \ - return paUnanticipatedHostError; \ - } \ - else \ - printf("call at line %d succeeded\n", __LINE__); \ - } - - if( stream->pcm_capture ) - { - ENSURE( snd_pcm_prepare( stream->pcm_capture ) ); - } - - if( stream->pcm_playback ) - { - const snd_pcm_channel_area_t *playback_areas, *area; - snd_pcm_uframes_t offset, frames; - int sample_size = Pa_GetSampleSize( stream->playback_hostsampleformat ); - printf("Sample size: %d\n", sample_size ); - ENSURE( snd_pcm_prepare( stream->pcm_playback ) ); - frames = snd_pcm_avail_update( stream->pcm_playback ); - printf("frames: %d\n", (int)frames ); - printf("channels: %d\n", stream->playback_channels ); - - snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas, &offset, &frames ); - - /* Insert silence */ - if( stream->playback_interleaved ) - { - void *playback_buffer; - area = &playback_areas[0]; - playback_buffer = area->addr + (area->first + area->step * offset) / 8; - memset( playback_buffer, 0, - frames * stream->playback_channels * sample_size ); - } - else - { - int i; - for( i = 0; i < stream->playback_channels; i++ ) - { - void *channel_buffer; - area = &playback_areas[i]; - channel_buffer = area->addr + (area->first + area->step * offset) / 8; - memset( channel_buffer, 0, frames * sample_size ); - } - } - - snd_pcm_mmap_commit( stream->pcm_playback, offset, frames ); - } - - if( stream->callback_mode ) - { - ENSURE( pthread_create( &stream->callback_thread, NULL, &CallbackThread, stream ) ); - - /* we'll do the snd_pcm_start() in the callback thread */ - } - else - { - if( stream->pcm_capture ) - snd_pcm_start( stream->pcm_capture ); - if( stream->pcm_playback ) - snd_pcm_start( stream->pcm_playback ); - } - - /* On my machine, the pcm stream will not transition to the RUNNING - * state for a while after snd_pcm_start is called. The PortAudio - * client needs to be able to depend on Pa_IsStreamActive() returning - * true the second after this function returns. So I sleep briefly here. - * - * I don't like this one bit. - */ - Pa_Sleep( 100 ); - - stream->callback_finished = 0; - - return result; -} - - -static PaError StopStream( PaStream *s ) -{ - PaError result = paNoError; - PaAlsaStream *stream = (PaAlsaStream*)s; - - /* First deal with the callback thread, cancelling and/or joining - * it if necessary - */ - - if( stream->callback_mode && stream->callback_finished ) - { - /* We are running in callback mode but the callback thread has - * already been cancelled by the return value from the user's - * callback function. Therefore we don't need to cancel the - * thread, but we do want to wait for it. */ - pthread_join( stream->callback_thread, NULL ); - } - else if( stream->callback_mode ) - { - /* We are running in callback mode, and the callback thread - * is still running. Cancel it and wait for it to be done. */ - pthread_cancel( stream->callback_thread ); - pthread_join( stream->callback_thread, NULL ); - } - - /* Stop the ALSA streams if necessary */ - - if( stream->callback_mode && stream->callback_finished ) - { - /* If we are in the callback_finished state the callback thread - * already stopped the streams. So there is nothing to do here. - */ - } - else - { - if( stream->pcm_capture ) - { - snd_pcm_drain( stream->pcm_capture ); - } - - if( stream->pcm_playback ) - { - snd_pcm_drain( stream->pcm_playback ); - } - } - - stream->callback_finished = 0; - - return result; -} - - -static PaError AbortStream( PaStream *s ) -{ - PaError result = paNoError; - PaAlsaStream *stream = (PaAlsaStream*)s; - - /* First deal with the callback thread, cancelling and/or joining - * it if necessary - */ - - if( stream->callback_mode && stream->callback_finished ) - { - /* We are running in callback mode but the callback thread has - * already been cancelled by the return value from the user's - * callback function. Therefore we don't need to cancel the - * thread, but we do want to wait for it. */ - pthread_join( stream->callback_thread, NULL ); - } - else if( stream->callback_mode ) - { - /* We are running in callback mode, and the callback thread - * is still running. Cancel it and wait for it to be done. */ - pthread_cancel( stream->callback_thread ); - pthread_join( stream->callback_thread, NULL ); - } - - /* Stop the ALSA streams if necessary */ - - if( stream->callback_mode && stream->callback_finished ) - { - /* If we are in the callback_finished state the callback thread - * already stopped the streams. So there is nothing to do here. - */ - } - else - { - if( stream->pcm_capture ) - { - snd_pcm_drop( stream->pcm_capture ); - } - - if( stream->pcm_playback ) - { - snd_pcm_drop( stream->pcm_playback ); - } - } - - stream->callback_finished = 0; - - return result; -} - - -static PaError IsStreamStopped( PaStream *s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - if( IsStreamActive(s) || stream->callback_finished ) - return 0; - else - return 1; -} - - -static PaError IsStreamActive( PaStream *s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - if( stream->pcm_capture ) - { - snd_pcm_state_t capture_state = snd_pcm_state( stream->pcm_capture ); - - if( capture_state == SND_PCM_STATE_RUNNING /*|| - capture_state == SND_PCM_STATE_PREPARED*/ ) - return 1; - } - - if( stream->pcm_playback ) - { - snd_pcm_state_t playback_state = snd_pcm_state( stream->pcm_playback ); - - if( playback_state == SND_PCM_STATE_RUNNING /*|| - playback_state == SND_PCM_STATE_PREPARED*/ ) - return 1; - } - - return 0; -} - - -static PaTime GetStreamTime( PaStream *s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - snd_output_t *output; - snd_timestamp_t timestamp; - snd_pcm_status_t *status; - snd_pcm_status_alloca( &status ); - - /* TODO: what if we have both? does it really matter? */ - - /* TODO: if running in callback mode, this will mean - * libasound routines are being called form multiple threads. - * need to verify that libasound is thread-safe. */ - - if( stream->pcm_capture ) - { - snd_pcm_status( stream->pcm_capture, status ); - } - else if( stream->pcm_playback ) - { - snd_pcm_status( stream->pcm_playback, status ); - } - - snd_pcm_status_get_tstamp( status, ×tamp ); - - return timestamp.tv_sec + ((float)timestamp.tv_usec/1000000); -} - - -static double GetStreamCpuLoad( PaStream* s ) -{ - PaAlsaStream *stream = (PaAlsaStream*)s; - - return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); -} - diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h deleted file mode 100644 index 62c9512c..00000000 --- a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h +++ /dev/null @@ -1,45 +0,0 @@ - -#include <alsa/asoundlib.h> - -#include <pthread.h> - -#include "pa_util.h" -#include "pa_process.h" -#include "pa_cpuload.h" -#include "pa_stream.h" - -typedef struct PaAlsaStream -{ - PaUtilStreamRepresentation streamRepresentation; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaUtilBufferProcessor bufferProcessor; - - snd_pcm_t *pcm_capture; - snd_pcm_t *pcm_playback; - - int callback_finished; /* bool: are we in the "callback finished" state? */ - - int frames_per_period; - int playback_hostsampleformat; - - int capture_channels; - int playback_channels; - - int capture_interleaved; /* bool: is capture interleaved? */ - int playback_interleaved; /* bool: is playback interleaved? */ - - int callback_mode; /* bool: are we running in callback mode? */ - pthread_t callback_thread; - - /* the callback thread uses these to poll the sound device, waiting - * for data to be ready/available */ - unsigned int capture_nfds; - unsigned int playback_nfds; - struct pollfd *pfds; - - /* these aren't really stream state, the callback uses them */ - snd_pcm_uframes_t capture_offset; - snd_pcm_uframes_t playback_offset; -} -PaAlsaStream; - |