Author: piumarta Date: 2010-04-13 07:51:56 -0700 (Tue, 13 Apr 2010) New Revision: 2201 Modified: trunk/platforms/unix/vm-sound-pulse/sqUnixSoundPulseAudio.c Log: adopt latest pulse audio driver from Scratch Modified: trunk/platforms/unix/vm-sound-pulse/sqUnixSoundPulseAudio.c =================================================================== --- trunk/platforms/unix/vm-sound-pulse/sqUnixSoundPulseAudio.c 2010-04-12 23:53:14 UTC (rev 2200) +++ trunk/platforms/unix/vm-sound-pulse/sqUnixSoundPulseAudio.c 2010-04-13 14:51:56 UTC (rev 2201) @@ -2,7 +2,7 @@ * * Author: Derek O'Connell <[hidden email]> * - * Copyright (C) 2009 by Derek O'Connel + * Copyright (C) 2009--2010 by Derek O'Connell * All rights reserved. * * This file is part of Unix Squeak. @@ -25,7 +25,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * Last edited: 2009-09-14 14:15:05 by piumarta on ubuntu.piumarta.com + * Last edited: 2010-04-13 07:45:37 by piumarta on ubuntu */ /* ========== */ @@ -150,8 +150,6 @@ int bytesPerFrame; /* PULSE, Simple API parameters */ - pa_stream_direction_t dir; - const char *stream_name; pa_simple *pa_conn; pa_sample_spec pa_spec; } audioIO_t; @@ -327,13 +325,6 @@ fprintf(stderr, "%0.0f usec \r", (float)latency); } -/* -static int bytesPerChannel(audioIO_t *audioIO) { - if ( PA_SAMPLE_S16LE == audioIO->rate) return SAMPLE_RATE_8KHZ; - PA_SAMPLE_S16LE -} -*/ - /* ================================== Signal Ops */ static void sigWait(gen_sig_t *sig) { @@ -446,20 +437,12 @@ } static int ioAllocBuffers(audioIO_t *audioIO, int frameCount) { - int maxBytes; int i; - /* NTS: should take audioIO->bytesPerFrame into account... - and that depends on stereo or not. Revisit at later date. - maxBytes = frameCount * audioIO->bytesPerFrame; - */ + /* Not preserving buffers when play/record stopped */ + /* Choosing memory conservation over speed of starting play/record */ - if (audioIO->buffersAllocated) - if (audioOut.maxSamples == frameCount) - return true; - else - ioFreeBuffers(audioIO); - + ioFreeBuffers(audioIO); audioIO->maxSamples = frameCount; audioIO->maxBytes = audioIO->maxSamples * audioIO->bytesPerFrame; audioIO->maxWords = audioIO->maxBytes >> 1; @@ -468,8 +451,6 @@ audioIO->buffer[i].isFree = true; } audioIO->buffersAllocated = true; - - return true; } static int ioIsFull(audioIO_t *audioIO) { @@ -584,10 +565,6 @@ /* if ((rc = snd_pcm_writei(audioOut.alsaHandle, buffer, frames)) < frames) { */ - /* Experiment to see if draining removes delay, result: undecided, seems slightly better */ - pa_simple_drain(audioOut.pa_conn, &rc); - - /* PA: Have to assume for now that all frames were written */ if (pa_simple_write(audioOut.pa_conn, buffer, (size_t) (frames * audioOut.bytesPerFrame), &rc) < 0) { fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(rc)); @@ -702,7 +679,7 @@ } */ - /* PA: Endian swap is N810 left-over... */ + /* PA: Endian swap may not be needed... */ /* Endian Swap (rc = frames = Word Count in this case) */ /* @@ -735,93 +712,20 @@ } -/* ================================== OPEN/CLOSE PA */ - -static int closePulseAudio(audioIO_t *audioIO) { - int rc; - - if (!audioIO->pa_conn) - return true; - - if (PA_STREAM_PLAYBACK == audioIO->dir) - if (pa_simple_drain(audioIO->pa_conn, &rc) < 0) - fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(rc)); - - pa_simple_free(audioIO->pa_conn); - audioIO->pa_conn = NULL; - - printf("closePulseAudio((): %s\n", audioIO->dbgName); - - return true; -} - -static int openPulseAudio(audioIO_t *audioIO, int samplesPerSec, int stereo) { - int rc; - int channels; - -/* -DBGMSG(">pa_Open()"); -#ifdef DBG -printf("\tframeCount: %d, samplesPerSec: %d, stereo: %d\n", frameCount, samplesPerSec, stereo, semaIndex); -#endif -*/ - - /* DMOC 090912: - Connection for playback stream should already have been opened when module loaded so - now only open if that failed or parameters have changed. Could also avoid buffer - creation if default frameCount known/agreed. - */ - - channels = stereo ? 2 : 1; - - /* If already connected then check if same spec */ - if (audioIO->pa_conn) - if ((audioIO->pa_spec.rate == samplesPerSec) && (audioIO->pa_spec.channels == channels)) - return true; - - if (audioIO->pa_conn) - closePulseAudio(audioIO); - - audioIO->pa_spec.rate = samplesPerSec; - audioIO->pa_spec.channels = channels; - - if (!(audioIO->pa_conn = pa_simple_new(NULL, "Scratch", audioIO->dir, NULL, audioIO->stream_name, &audioIO->pa_spec, NULL, NULL, &rc))) { - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(rc)); - return false; - } - -/* - if (PA_STREAM_PLAYBACK == audioIO->dir) - pa_simple_drain(audioIO->pa_conn, &rc); -*/ - printf("openPulseAudio() %s, rate: %i, chans: %i\n", audioIO->dbgName, samplesPerSec, channels); - - return true; -} - /* ================================== IO INIT */ -/* ioInit() called when module loaded... - N810: Threads pre-started and held on semaphore - PA: Connection opened for audio-out with default settings -*/ - static int ioInit() { - int rc; - if (initDone) return true; initDone = true; - /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ - /* >>>>>>>>>>>>> AUDIO OUT >>>>>>>>>>>> */ - /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ + /* AUDIO OUT */ /* NOT USED >>> */ audioOut.dbgName = "play"; audioOut.device = "pa-simple"; /* <<< */ - audioOut.open = false; /* Squeak state */ + audioOut.open = false; audioOut.maxSamples = 0; audioOut.maxWords = 0; @@ -856,35 +760,19 @@ audioOut.rateID = 0; audioOut.bytesPerFrame = 4; /* Stereo S16LE */ - /* PA Specific (defaults for Scratch/Squeak) */ - audioOut.dir = PA_STREAM_PLAYBACK; - audioOut.stream_name = "playback"; - audioOut.pa_spec.format = PA_SAMPLE_S16LE; /* Squeak default */ - audioOut.pa_spec.rate = 0; - audioOut.pa_spec.channels = 0; - audioOut.pa_conn = NULL; + audioOut.pa_conn = null; - /* Open PA connection here to avoid delays later on */ - openPulseAudio(&audioOut, 22050, true); - - /* Allocate buffers here to avoid delays later on */ - /* Hmmm, tricky because varies... so not doing it atm */ -/* ioAllocBuffers(&audioOut, frameCount); -*/ - ioThreadStart(&audioOut); + /* AUDIO IN */ - /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ - /* >>>>>>>>>>>>> AUDIO IN >>>>>>>>>>>>> */ - /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ + audioIn.dbgName = "rec"; /* NOT USED >>> */ - audioIn.dbgName = "rec"; audioIn.device = "pa-simple"; /* <<< */ - audioIn.open = false; /* Squeak state */ + audioIn.open = false; audioIn.maxSamples = 0; audioIn.maxWords = 0; @@ -919,16 +807,8 @@ audioIn.rateID = 0; audioIn.bytesPerFrame = 2; /* Mono S16LE */ - /* PA Specific */ - audioIn.dir = PA_STREAM_RECORD; - audioIn.stream_name = "record"; - audioIn.pa_spec.format = PA_SAMPLE_S16LE; /* Squeak default */ - audioIn.pa_spec.rate = 0; - audioIn.pa_spec.channels = 0; - audioIn.pa_conn = NULL; + audioIn.pa_conn = null; - /* DMOC 090912: Not attempting to open default PA connection for recording */ - ioThreadStart(&audioIn); } @@ -950,6 +830,7 @@ return 0; /* or maxBytes? */ } + static sqInt sound_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex) { unsigned int bufferNext, samples, sampleBytes; @@ -971,10 +852,9 @@ return 0; /* or maxBytes? */ } + static sqInt sound_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex) { int rc; - int channels; - int reopen; DBGMSG(">sound_Start()"); @@ -984,23 +864,33 @@ if (audioOut.open) return true; - if (!openPulseAudio(&audioOut, samplesPerSec, stereo)) { - success(false); - return false; + audioOut.pa_spec.format = PA_SAMPLE_S16LE; + audioOut.pa_spec.rate = samplesPerSec; /* rate(SAMPLE_RATE_22_05KHZ) for Squeak */ + audioOut.pa_spec.channels = stereo ? 2 : 1; + audioOut.pa_conn = NULL; + + /* Create a new playback stream */ + if (!(audioOut.pa_conn = pa_simple_new(NULL, "Scratch", PA_STREAM_PLAYBACK, NULL, "playback", &audioOut.pa_spec, NULL, NULL, &rc))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(rc)); + success(false); + return false; } - - printf("sound_Start() frameCount >> 1: %i\n", frameCount >> 1); - ioAllocBuffers(&audioOut, frameCount >> 1); + ioAllocBuffers(&audioOut, frameCount); + audioOut.bufferCount = audioOut.maxBuffers; /* Has to be reset everytime */ - /* EVERY TIME: Initialise buffer count, ie, Squeak-ready buffers (max for audio-out) */ - audioOut.bufferCount = audioOut.maxBuffers; - audioOut.sqSemaphore = semaIndex; + audioOut.open = true; sigSignal(&audioOut.sigRun); + /* error possibly left over from dsp-protocol.c code */ + /* dsp-protocol.c in current ALSA not capturing EINTR/EAGAIN */ + /* EINTR/EAGAIN from dsp-protocol.c not raised up to ALSA so not caught by ALSA */ + /* Clearing errno here to see if Squeak can continue regardless */ + errno = 0; + DBGMSG("<sound_Start()"); return true; } @@ -1018,10 +908,16 @@ ioThreadStall(&audioOut); - closePulseAudio(&audioOut); + if (pa_simple_drain(audioOut.pa_conn, &rc) < 0) { + fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(rc)); + } + + if (NULL != audioOut.pa_conn) + pa_simple_free(audioOut.pa_conn); ioFreeBuffers(&audioOut); + audioOut.pa_conn = NULL; audioOut.sqSemaphore = 0; DBGMSG("<sound_Stop()"); @@ -1034,30 +930,57 @@ static sqInt sound_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex) { int rc; + pa_buffer_attr pa_buffer_metrics; /* For recording */ DBGMSG(">sound_StartRecording()"); if (audioIn.open) return true; + audioIn.pa_spec.format = PA_SAMPLE_S16LE; + audioIn.pa_spec.rate = desiredSamplesPerSec; + audioIn.pa_spec.channels = stereo ? 2 : 1; + audioIn.pa_conn = NULL; + + pa_buffer_metrics.maxlength = (uint32_t) -1; + pa_buffer_metrics.tlength = (uint32_t) -1; /* playback only */ + pa_buffer_metrics.prebuf = (uint32_t) -1; /* playback only */ + pa_buffer_metrics.minreq = (uint32_t) -1; /* playback only */ + pa_buffer_metrics.fragsize = pa_usec_to_bytes(20*1000, &audioIn.pa_spec); + + /* Create the recording stream */ + if (!(audioIn.pa_conn = pa_simple_new( NULL, + "Scratch", + PA_STREAM_RECORD, + NULL, + "record", + &audioIn.pa_spec, + NULL, + &pa_buffer_metrics, + &rc))) + { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(rc)); + success(false); + return false; + } + /* Only rate supported on the N810 (atm) is 8000 */ /* - desiredSamplesPerSec = 8000; + audioIn.alsaRate = 8000; */ - if (!openPulseAudio(&audioIn, desiredSamplesPerSec, stereo)) { - success(false); - return false; - } - - /* Buffers will be filled before signalling Squeak. So rate & buffer size determined signalling freq... */ /* 20Hz update freq for Squeak sounds reasonable, so... */ audioIn.maxSamples = audioIn.pa_spec.rate / 20; - ioAllocBuffers(&audioIn, audioIn.maxSamples); - - /* EVERY TIME: Initialise buffer count, ie, Squeak-ready buffers (ZERO for audio-in) */ - audioIn.bufferCount = 0; + /* Use a buffer large enough to hold one period (assuming 2 bytes/sample) */ +/* + audioIn.alsaBufferSize = audioIn.maxSamples * 2 * audioIn.pa_spec.channels; + audioIn.alsaBuffer = (char *) malloc(audioIn.alsaBufferSize); +*/ + /* Buffers will be filled before signalling Squeak. So rate & buffer size determined signalling freq... */ + ioAllocBuffers(&audioIn, audioIn.pa_spec.rate / 20 ); /* for Sq signalling rate of 20Hz */ + audioIn.bufferCount = 0; /* Has to be reset everytime */ + audioIn.sqSemaphore = semaIndex; audioIn.open = true; @@ -1078,7 +1001,7 @@ ioThreadStall(&audioIn); - closePulseAudio(&audioIn); + pa_simple_free(audioIn.pa_conn); ioFreeBuffers(&audioIn); @@ -1189,7 +1112,7 @@ #include "SqSound.h" -SqSoundDefine(pulse); +SqSoundDefine(PA); #include "SqModule.h" @@ -1235,12 +1158,13 @@ } static void *sound_makeInterface(void) { -//#ifdef NEWSIG +/*#ifdef NEWSIG // sigalrm_save(); // DMOC: Being here assumes old handler same for run duration! Same for sigio handler. //#else // DMOC: Rethink: Signal captured once, preserved and restored when/where necessary? // sigio_save(); //#endif +*/ #ifdef USE_RESOURCE_MANAGER printf("USE_RESOURCE_MANAGER\n"); @@ -1248,7 +1172,7 @@ ioInit(); - return &sound_pulse_itf; + return &sound_PA_itf; } SqModuleDefine(sound, pulse); |
Free forum by Nabble | Edit this page |