~drgeo-developers/drgeo/trunk

« back to all changes in this revision

Viewing changes to VMs/iPad/source/unix/vm-sound-pulse/sqUnixSoundPulseAudio.c

  • Committer: Hilaire Fernandes
  • Date: 2012-01-27 21:15:40 UTC
  • Revision ID: hilaire.fernandes@gmail.com-20120127211540-912spf97bhpx6mve
Initial additions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* sqUnixSoundPulseAudio.c -- sound module for Pulse Audio
 
2
 *
 
3
 * Author: Derek O'Connell <doc@doconnel.f9.co.uk>
 
4
 * 
 
5
 *   Copyright (C) 2009--2010 by Derek O'Connell
 
6
 *   All rights reserved.
 
7
 *   
 
8
 *   This file is part of Unix Squeak.
 
9
 * 
 
10
 *   Permission is hereby granted, free of charge, to any person obtaining a
 
11
 *   copy of this software and associated documentation files (the "Software"),
 
12
 *   to deal in the Software without restriction, including without limitation
 
13
 *   the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
14
 *   and/or sell copies of the Software, and to permit persons to whom the
 
15
 *   Software is furnished to do so, subject to the following conditions:
 
16
 * 
 
17
 *   The above copyright notice and this permission notice shall be included in
 
18
 *   all copies or substantial portions of the Software.
 
19
 * 
 
20
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
21
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
22
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
23
 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
24
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
25
 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
26
 *   DEALINGS IN THE SOFTWARE.
 
27
 *
 
28
 * Last edited: 2010-04-13 07:45:37 by piumarta on ubuntu
 
29
 */
 
30
 
 
31
/* ========== */
 
32
/* INCLUDES   */
 
33
/* ========== */
 
34
 
 
35
#include "sq.h"
 
36
#include <errno.h>
 
37
#include <signal.h>
 
38
 
 
39
#include <stdio.h>
 
40
#include <stdlib.h>
 
41
#include <sys/errno.h>
 
42
#include <sys/mman.h>
 
43
#include <string.h>
 
44
#include <unistd.h>
 
45
 
 
46
/*
 
47
#include <glib.h>
 
48
*/
 
49
#include <pthread.h>
 
50
 
 
51
#include <pulse/simple.h>
 
52
#include <pulse/error.h>
 
53
/*
 
54
#include <pulse/gccmacro.h>
 
55
*/
 
56
 
 
57
/* ========== */
 
58
/* MACROS     */
 
59
/* ========== */
 
60
 
 
61
#define FAIL(X)   \
 
62
{     \
 
63
        success(false); \
 
64
        return X;   \
 
65
}
 
66
 
 
67
#define snd(expr, what)                                         \
 
68
  if ((rc = snd_##expr) < 0)                                    \
 
69
    {                                                           \
 
70
      fprintf(stderr, "%s: %s\n", what, snd_strerror(rc));      \
 
71
      success(false);                                           \
 
72
      return rc;                                                \
 
73
    }
 
74
 
 
75
 
 
76
/* ================================== DEBUGGING  */
 
77
 
 
78
#define xDBG
 
79
 
 
80
#ifdef DBG
 
81
        #define DBG_MSG_MAX_LEN 128
 
82
 
 
83
        char *dbg_msg[DBG_MSG_MAX_LEN];
 
84
 
 
85
        #define DBGMSG(M) { \
 
86
                printf("DBG: sqUnixSoundMaemo: %s (%d, %s)\n", M, errno, strerror (errno)); \
 
87
                errno = 0; \
 
88
        }
 
89
 
 
90
        #define DBGERR(M, E) { \
 
91
                sprintf(*dbg_msg, M, E); \
 
92
                DBGMSG(dbg_msg); \
 
93
        }
 
94
 
 
95
#else
 
96
        #define DBGMSG(M) 
 
97
        #define DBGERR(M, E)
 
98
#endif
 
99
 
 
100
 
 
101
/* ================================== TYPES */
 
102
 
 
103
typedef struct {
 
104
        short *buffer;
 
105
        unsigned long samples;
 
106
        int isFree;
 
107
} audioBuffer_t;
 
108
 
 
109
typedef struct {
 
110
        pthread_mutex_t *mutex;
 
111
        pthread_cond_t  *cond;
 
112
        unsigned int count;
 
113
} gen_sig_t;
 
114
 
 
115
typedef struct {
 
116
        /* Left in for debugging >>> */
 
117
        const char *dbgName;
 
118
        const char *device;
 
119
        /* <<< */
 
120
        
 
121
        int open;
 
122
        
 
123
        unsigned long maxSamples;
 
124
        unsigned long maxWords;
 
125
        unsigned long maxBytes;
 
126
        
 
127
        audioBuffer_t *buffer;
 
128
        
 
129
        int maxBuffers;
 
130
        int buffersAllocated;
 
131
        int bufferFree;
 
132
        int bufferNext;
 
133
        int bufferCount;
 
134
        int bufferFull;
 
135
        
 
136
        pthread_mutex_t *bufferMutex;
 
137
        
 
138
        void *          threadFunc;
 
139
        pthread_t thread;
 
140
 
 
141
        gen_sig_t sigRun;
 
142
        gen_sig_t sigStalled;
 
143
        
 
144
        int running;
 
145
        int exit;
 
146
        int stall;
 
147
        int sqSemaphore;
 
148
        
 
149
        int rateID;
 
150
        int bytesPerFrame;
 
151
        
 
152
        /* PULSE, Simple API parameters */
 
153
        pa_simple *pa_conn;
 
154
  pa_sample_spec pa_spec;
 
155
 } audioIO_t;
 
156
 
 
157
 
 
158
/* ================================== FUNCTION PROTOTYPES */
 
159
 
 
160
static int rate(int rateID);
 
161
static int rateID(int rate);
 
162
 
 
163
static inline unsigned short _swapw(unsigned short v); /* From io.h */
 
164
 
 
165
static int devInputReady(int dev_fd);
 
166
 
 
167
static void sigWait(gen_sig_t *sig);
 
168
static void sigReset(gen_sig_t *sig);
 
169
static void sigSignal(gen_sig_t *sig);
 
170
 
 
171
static void ioThreadWaitToRun(audioIO_t *audioIO);
 
172
static void ioThreadExit(audioIO_t *audioIO);
 
173
static int  ioThreadStart(audioIO_t *audioIO);
 
174
static int  ioThreadIsRunning(audioIO_t *audioIO);
 
175
static void ioThreadStall(audioIO_t *audioIO);
 
176
 
 
177
static void ioZeroBuffers(audioIO_t *audioIO);
 
178
static void ioFreeBuffers(audioIO_t *audioIO);
 
179
static int  ioFreeBytes(audioIO_t *audioIO);
 
180
static int  ioIsFull(audioIO_t *audioIO);
 
181
static int  ioAddPlayBuffer(void *buffer, int frameCount);
 
182
static int  ioGetRecordBuffer(void *buffer, int bufferBytes);
 
183
static int  ioAllocBuffers(audioIO_t *audioIO, int frameCount);
 
184
static int  ioGetBufferData(audioIO_t *audioIO, void **buffer, int *frames);
 
185
static int  ioNextBuffer(audioIO_t *audioIO);
 
186
 
 
187
static void *writerThread(void *ptr);
 
188
static void *readerThread(void *ptr);
 
189
 
 
190
static int  ioInit();
 
191
 
 
192
/* SQUEAK INTERFACE */
 
193
 
 
194
static int trace();
 
195
 
 
196
static sqInt sound_AvailableSpace(void);
 
197
static sqInt sound_InsertSamplesFromLeadTime(int frameCount, int srcBufPtr, int samplesOfLeadTime);
 
198
static sqInt sound_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex);
 
199
static sqInt sound_PlaySilence(void);
 
200
static sqInt sound_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex);
 
201
static sqInt sound_Stop(void);
 
202
 
 
203
static sqInt sound_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex);
 
204
static sqInt sound_StopRecording(void);
 
205
static double sound_GetRecordingSampleRate(void);
 
206
static sqInt sound_RecordSamplesIntoAtLength(int buf, int startSliceIndex, int bufferSizeInBytes);
 
207
 
 
208
static int mixer_open(char *name);
 
209
static void mixer_close(void);
 
210
static inline void mixer_getVolume(char *name, int captureFlag, double *leftLevel, double *rightLevel);
 
211
static inline void mixer_setVolume(char *name, int captureFlag, double leftLevel, double rightLevel);
 
212
static int mixer_setSwitch(char *name, int captureFlag, int parameter);
 
213
static int mixer_getSwitch(char *name, int captureFlag, int channel);
 
214
static void sound_Volume(double *left, double *right);
 
215
static void sound_SetVolume(double left, double right);
 
216
static sqInt sound_SetRecordLevel(sqInt level);
 
217
static sqInt sound_SetDevice(sqInt id, char *arg);
 
218
static sqInt sound_GetSwitch(sqInt id, sqInt captureFlag, sqInt channel);
 
219
static sqInt sound_SetSwitch(sqInt id, sqInt captureFlag, sqInt parameter);
 
220
 
 
221
 
 
222
/* ====================                                 */
 
223
/* ==================== GLOBALS */
 
224
/* ====================                                 */
 
225
 
 
226
/* Left in but not used >>> */
 
227
#define SQ_SND_PLAY_START_THRESHOLD     7/8
 
228
#define SQ_SND_PLAY_AVAIL_MIN           4/8
 
229
/* <<< */
 
230
 
 
231
/* Arbitrary (apart from minmising latency) >>> */
 
232
#define MAX_INPUT_BUFFERS 10
 
233
#define MAX_OUTPUT_BUFFERS 2
 
234
/* <<< */
 
235
 
 
236
audioBuffer_t iBuffer[MAX_INPUT_BUFFERS];
 
237
audioBuffer_t oBuffer[MAX_OUTPUT_BUFFERS];
 
238
 
 
239
/* STATICALLY INITIALISED SO AUTO-DESTROYED (ON CRASHING FOR INSTANCE) >>> */
 
240
 
 
241
/* input */
 
242
 
 
243
pthread_mutex_t audioInBufferMutex              = PTHREAD_MUTEX_INITIALIZER;
 
244
 
 
245
pthread_mutex_t audioInRunMutex                         = PTHREAD_MUTEX_INITIALIZER;
 
246
pthread_cond_t  audioInRunCond                          = PTHREAD_COND_INITIALIZER;
 
247
 
 
248
pthread_mutex_t audioInStalledMutex             = PTHREAD_MUTEX_INITIALIZER;
 
249
pthread_cond_t  audioInStalledCond              = PTHREAD_COND_INITIALIZER;
 
250
 
 
251
/* output */
 
252
 
 
253
pthread_mutex_t audioOutBufferMutex             = PTHREAD_MUTEX_INITIALIZER;
 
254
 
 
255
pthread_mutex_t audioOutRunMutex                        = PTHREAD_MUTEX_INITIALIZER;
 
256
pthread_cond_t  audioOutRunCond                         = PTHREAD_COND_INITIALIZER;
 
257
 
 
258
pthread_mutex_t audioOutStalledMutex    = PTHREAD_MUTEX_INITIALIZER;
 
259
pthread_cond_t  audioOutStalledCond             = PTHREAD_COND_INITIALIZER;
 
260
 
 
261
/* <<< */
 
262
 
 
263
 
 
264
audioIO_t audioIn, audioOut;
 
265
 
 
266
int initDone = false;
 
267
 
 
268
/* EXTRA FOR ALSA BUT UNUSED >>> */
 
269
/*
 
270
static int              output_buffer_frames_available = 1;
 
271
static double   max_delay_frames = 0;
 
272
*/
 
273
/* <<< */
 
274
 
 
275
 
 
276
/* ================================== UTILS */
 
277
 
 
278
/* RATE CONVERSION: from dsp code but not used (yet). Maybe not needed at all with AlSA */
 
279
/* RATE CONVERSION: fixed preset rates are used. TBD: choose nearest to requested */
 
280
/*
 
281
static int rate(int rateID) {
 
282
        if (SAMPLE_RATE_8KHZ            == rateID) return  8000;
 
283
        if (SAMPLE_RATE_16KHZ           == rateID) return 16000;
 
284
        if (SAMPLE_RATE_11_025KHZ == rateID) return 11025;
 
285
        if (SAMPLE_RATE_22_05KHZ  == rateID) return 22050;
 
286
        if (SAMPLE_RATE_44_1KHZ   == rateID) return 44100;
 
287
        return -1;
 
288
}
 
289
 
 
290
static int rateID(int rate) {
 
291
        if ( 8000 == rate) return SAMPLE_RATE_8KHZ;
 
292
        if ( 8192 == rate) return SAMPLE_RATE_8KHZ;
 
293
        if (16000 == rate) return SAMPLE_RATE_16KHZ;
 
294
        if (11025 == rate) return SAMPLE_RATE_11_025KHZ;
 
295
        if (22050 == rate) return SAMPLE_RATE_22_05KHZ;
 
296
        if (44100 == rate) return SAMPLE_RATE_44_1KHZ;
 
297
        return -1;
 
298
}
 
299
*/
 
300
 
 
301
/* From io.h because recorded data has to be Big Endian */
 
302
static inline unsigned short _swapw(unsigned short v) {
 
303
        return ((v << 8) | (v >> 8));
 
304
}
 
305
 
 
306
 
 
307
/* Not used but maybe useful */
 
308
/*
 
309
static int devInputReady(int dev_fd) {
 
310
        struct pollfd pfd;
 
311
        pfd.fd = dev_fd;
 
312
        pfd.events = POLLIN;
 
313
        if (poll (&pfd,1,0)>0) return true;
 
314
        return false;
 
315
}
 
316
*/
 
317
 
 
318
static void printPALatency() {
 
319
        pa_usec_t latency;
 
320
        int error;
 
321
        
 
322
        if ((latency = pa_simple_get_latency(audioOut.pa_conn, &error)) == (pa_usec_t) -1)
 
323
                fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
 
324
        else
 
325
                fprintf(stderr, "%0.0f usec    \r", (float)latency);
 
326
}
 
327
 
 
328
/* ================================== Signal Ops */
 
329
 
 
330
static void sigWait(gen_sig_t *sig) {
 
331
        pthread_mutex_lock(sig->mutex);
 
332
                while( !sig->count )
 
333
                        pthread_cond_wait(sig->cond, sig->mutex);
 
334
                sig->count -= 1;
 
335
        pthread_mutex_unlock(sig->mutex);
 
336
}
 
337
 
 
338
static void sigReset(gen_sig_t *sig) {
 
339
        pthread_mutex_lock(sig->mutex);
 
340
                sig->count = 0;
 
341
        pthread_mutex_unlock(sig->mutex);
 
342
}
 
343
 
 
344
static void sigSignal(gen_sig_t *sig) {
 
345
        pthread_mutex_lock(sig->mutex);
 
346
                sig->count += 1;
 
347
                pthread_cond_signal(sig->cond);
 
348
        pthread_mutex_unlock(sig->mutex);
 
349
}
 
350
 
 
351
/* Here for debugging but direct calls would be ok >>> */
 
352
static void signalSqueak(audioIO_t *audioIO) {
 
353
/*      printf("@%d",audioIO->sqSemaphore);
 
354
*/
 
355
        if (0 < audioIO->sqSemaphore)
 
356
                signalSemaphoreWithIndex(audioIO->sqSemaphore);
 
357
}
 
358
/* <<< */
 
359
 
 
360
 
 
361
/* ================================== Thread Ops */
 
362
 
 
363
static void ioThreadExit(audioIO_t *audioIO) {
 
364
        if (!audioIO->thread) return;
 
365
        audioIO->exit = 1;
 
366
        sigSignal(&audioIO->sigRun);
 
367
        pthread_join(audioIO->thread, NULL);
 
368
        audioIO->thread = 0;
 
369
}
 
370
 
 
371
static int ioThreadStart(audioIO_t *audioIO) {
 
372
        int rc;
 
373
        if (audioIO->thread) return true;
 
374
        rc = pthread_create(&audioIO->thread, NULL, audioIO->threadFunc, NULL);
 
375
        if (0 != rc) DBGERR("ioThreadStart(): %d", rc);
 
376
        return rc;
 
377
}
 
378
 
 
379
static int ioThreadIsRunning(audioIO_t *audioIO) {
 
380
        return audioIO->running;
 
381
}
 
382
 
 
383
static void ioThreadStall(audioIO_t *audioIO) {
 
384
        audioIO->stall = true;
 
385
        sigSignal(&audioIO->sigRun);
 
386
        sigWait(&audioIO->sigStalled);
 
387
}
 
388
 
 
389
/* Don't attempt to signal Sq here as we may not have a semaphore! */
 
390
static void ioThreadWaitToRun(audioIO_t *audioIO) {
 
391
        sigSignal(&audioIO->sigStalled);
 
392
        
 
393
        pthread_mutex_lock(audioIO->sigRun.mutex);
 
394
                audioIO->running = false;
 
395
                
 
396
                if (audioIO->stall) audioIO->sigRun.count = 0;
 
397
                audioIO->stall = false;
 
398
                
 
399
                while( !audioIO->sigRun.count )
 
400
                        pthread_cond_wait(audioIO->sigRun.cond, audioIO->sigRun.mutex);
 
401
                audioIO->sigRun.count -= 1;
 
402
        
 
403
                audioIO->running = true;
 
404
        pthread_mutex_unlock(audioIO->sigRun.mutex);
 
405
        
 
406
        sigReset(&audioIO->sigStalled);         
 
407
}
 
408
 
 
409
/* ================================== Buffer ops */
 
410
 
 
411
static void ioZeroBuffers(audioIO_t *audioIO) {
 
412
        int i;
 
413
        for(i=0; i < audioIO->maxBuffers; i++) {
 
414
                audioIO->buffer[i].samples = 0;
 
415
                audioIO->buffer[i].isFree  = true;
 
416
        }
 
417
}
 
418
 
 
419
static void ioFreeBuffers(audioIO_t *audioIO) {
 
420
        int i;
 
421
        for(i=0; i < audioIO->maxBuffers; i++) {
 
422
                free(audioIO->buffer[i].buffer);
 
423
                audioIO->buffer[i].buffer  = 0;
 
424
                audioIO->buffer[i].samples = 0;
 
425
        }
 
426
        audioIO->bufferFree  = audioIO->bufferNext = 0;
 
427
        /* audioIO->bufferCount differs for play/record */
 
428
}
 
429
 
 
430
/* Only used for playing, not for recording */
 
431
static int ioFreeBytes(audioIO_t *audioIO) {
 
432
        int freeBytes;
 
433
        pthread_mutex_lock(audioIO->bufferMutex);
 
434
                freeBytes = audioIO->maxBytes * audioIO->bufferCount;
 
435
        pthread_mutex_unlock(audioIO->bufferMutex);
 
436
        return freeBytes;
 
437
}
 
438
 
 
439
static int ioAllocBuffers(audioIO_t *audioIO, int frameCount) {
 
440
        int i;
 
441
        
 
442
        /* Not preserving buffers when play/record stopped */
 
443
        /* Choosing memory conservation over speed of starting play/record */
 
444
        
 
445
        ioFreeBuffers(audioIO);
 
446
        audioIO->maxSamples = frameCount;
 
447
        audioIO->maxBytes   = audioIO->maxSamples * audioIO->bytesPerFrame;
 
448
        audioIO->maxWords   = audioIO->maxBytes >> 1;
 
449
        for(i=0; i < audioIO->maxBuffers; i++) {
 
450
                audioIO->buffer[i].buffer = (short *)calloc(audioIO->maxBytes, 1);
 
451
                audioIO->buffer[i].isFree = true;
 
452
        }
 
453
        audioIO->buffersAllocated = true;
 
454
}
 
455
 
 
456
static int ioIsFull(audioIO_t *audioIO) {
 
457
        pthread_mutex_lock(audioIO->bufferMutex);
 
458
                audioIO->bufferFull = (0 < audioIO->buffer[audioIO->bufferFree].samples);
 
459
        pthread_mutex_unlock(audioIO->bufferMutex);
 
460
        return audioIO->bufferFull;
 
461
}
 
462
 
 
463
/* Could combine some of the following but makes debugging difficult */
 
464
 
 
465
static int ioAddPlayBuffer(void *buffer, int frameCount) {
 
466
        long bytes;
 
467
        if (ioIsFull(&audioOut)) return 0;
 
468
        pthread_mutex_lock(audioOut.bufferMutex);
 
469
                bytes = MIN(audioOut.maxBytes, frameCount * audioOut.bytesPerFrame);
 
470
                memcpy(audioOut.buffer[audioOut.bufferFree].buffer, buffer, bytes);
 
471
                audioOut.buffer[audioOut.bufferFree].samples = frameCount;
 
472
                audioOut.buffer[audioOut.bufferFree].isFree  = false;
 
473
                audioOut.bufferFree = (audioOut.bufferFree + 1) % audioOut.maxBuffers;
 
474
                audioOut.bufferCount -= 1;
 
475
        pthread_mutex_unlock(audioOut.bufferMutex);
 
476
        return bytes;
 
477
}
 
478
 
 
479
static int ioGetRecordBuffer(void *buffer, int bufferBytes) {
 
480
        long samples, sampleBytes;
 
481
        
 
482
        if (bufferBytes <= 0) return 0;
 
483
/*      if (audioIn.buffer[audioIO->bufferNext].samples <=0) return 0;
 
484
*/      
 
485
        if (audioIn.buffer[audioIn.bufferNext].isFree) return 0;
 
486
        
 
487
        pthread_mutex_lock(audioIn.bufferMutex);
 
488
                samples = audioIn.buffer[audioIn.bufferNext].samples;
 
489
                sampleBytes = MIN(2 * audioIn.pa_spec.channels * samples, bufferBytes);
 
490
                memcpy(buffer, (char *)audioIn.buffer[audioIn.bufferNext].buffer, sampleBytes);
 
491
        /* DMOC 090909 1800: Hmmmm, what if Squeak does not read whole buffer? ATM remaining buffer data lost since */
 
492
        /*   ioGetRecordBuffer() frees the buffer after single visit. Needs more work */
 
493
                audioIn.buffer[audioIn.bufferNext].samples = 0;
 
494
                audioIn.buffer[audioIn.bufferNext].isFree = true;
 
495
                audioIn.bufferNext = (audioIn.bufferNext + 1) % audioIn.maxBuffers;
 
496
                audioIn.bufferCount -= 1;
 
497
        pthread_mutex_unlock(audioIn.bufferMutex);
 
498
        return sampleBytes;
 
499
}
 
500
 
 
501
static int ioGetBufferData(audioIO_t *audioIO, void **buffer, int *frames) {
 
502
        if (audioIO->buffer[audioIO->bufferNext].isFree) return false;
 
503
        pthread_mutex_lock(audioIO->bufferMutex);
 
504
                *buffer = (void *)(audioIO->buffer[audioIO->bufferNext].buffer);
 
505
                *frames = audioIO->buffer[audioIO->bufferNext].samples;
 
506
        pthread_mutex_unlock(audioIO->bufferMutex);
 
507
        return true;
 
508
}
 
509
 
 
510
static int ioNextPlayBuffer() {
 
511
        pthread_mutex_lock(audioOut.bufferMutex);
 
512
                audioOut.buffer[audioOut.bufferNext].samples = 0;
 
513
                audioOut.buffer[audioOut.bufferNext].isFree  = true;
 
514
                audioOut.bufferNext = (audioOut.bufferNext + 1) % audioOut.maxBuffers;
 
515
                audioOut.stall = (audioOut.bufferNext == audioOut.bufferFree);
 
516
                audioOut.bufferCount += 1;
 
517
        pthread_mutex_unlock(audioOut.bufferMutex);
 
518
}
 
519
 
 
520
static int ioNextRecordBuffer() {
 
521
        pthread_mutex_lock(audioIn.bufferMutex);
 
522
                audioIn.buffer[audioIn.bufferNext].isFree  = false;
 
523
                audioIn.bufferFree = (audioIn.bufferNext + 1) % audioIn.maxBuffers;
 
524
                audioIn.stall = (audioIn.bufferNext == audioIn.bufferFree);
 
525
                audioIn.bufferCount += 1;
 
526
        pthread_mutex_unlock(audioIn.bufferMutex);
 
527
}
 
528
 
 
529
/* ================================== IO THREADS */
 
530
 
 
531
static void *writerThread(void *ptr) {
 
532
        struct timespec tm = {0, 1000 * 1000};
 
533
        int rc;
 
534
        int nextBuffer, frames;
 
535
        void *buffer;
 
536
        
 
537
        DBGMSG("[writerThread: started]");
 
538
        
 
539
        audioOut.exit = 0;
 
540
 
 
541
        for (;;) {
 
542
                DBGMSG("[writerThread: waiting]");
 
543
                
 
544
                /* No point signalling squeak *before* running as there may not be a semaphore */
 
545
                ioThreadWaitToRun(&audioOut);
 
546
 
 
547
                if (audioOut.exit) break;
 
548
                if (!audioOut.open || audioOut.stall) continue;
 
549
                
 
550
                DBGMSG("[writerThread: running]");
 
551
                
 
552
                for (;;) {
 
553
                        if (!audioOut.open || audioOut.stall || audioOut.exit) break;
 
554
 
 
555
                        if (!ioGetBufferData(&audioOut, &buffer, &frames)) {
 
556
                                signalSqueak(&audioOut);
 
557
                                break;
 
558
                        }
 
559
                        
 
560
/*printf("writerThread: buffer: %d, frames %d\n", audioOut.bufferNext, frames);
 
561
*/
 
562
                        
 
563
                        while (frames > 0) {
 
564
                                if (!audioOut.open || audioOut.stall || audioOut.exit) break;
 
565
/*                              if ((rc = snd_pcm_writei(audioOut.alsaHandle, buffer, frames)) < frames) {
 
566
*/
 
567
        
 
568
        /* PA: Have to assume for now that all frames were written */
 
569
        if (pa_simple_write(audioOut.pa_conn, buffer, (size_t) (frames * audioOut.bytesPerFrame), &rc) < 0) {
 
570
          fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(rc));
 
571
/*                                      printf("writerThread: sent %d, actual %d\n", frames, rc);
 
572
*/
 
573
                                        break;
 
574
                                }
 
575
                                
 
576
        /* PA: Have to assume for now that all frames were written */
 
577
/*                              buffer = (short *)((char *)buffer + rc * audioOut.bytesPerFrame);
 
578
                                frames -= rc;
 
579
*/
 
580
                                /* *** SO FOLLOWING CODE *AND* THE ENCLOSING WHILE-LOOP REDUNDANT!!! (so just break out of loop) *** */
 
581
/*                              buffer = (short *)((char *)buffer + frames * audioOut.bytesPerFrame);
 
582
                                frames -= frames;
 
583
*/
 
584
                                break;
 
585
                        } /* while */
 
586
                        
 
587
                        if (!audioOut.open || audioOut.stall || audioOut.exit) break;
 
588
                        ioNextPlayBuffer();     
 
589
                        if (!audioOut.open || audioOut.stall || audioOut.exit) break;
 
590
                        
 
591
                        signalSqueak(&audioOut);
 
592
                }
 
593
                
 
594
                if (audioOut.exit) break;
 
595
        }
 
596
 
 
597
        DBGMSG("[writerThread: stopped]");
 
598
 
 
599
}
 
600
 
 
601
 
 
602
static void *readerThread(void *ptr) {
 
603
        int rc;
 
604
        int wc;
 
605
        unsigned short *p;
 
606
 
 
607
        DBGMSG("[readerThread: started]");
 
608
        
 
609
        audioIn.exit = 0;
 
610
        
 
611
        for (;;) {
 
612
                DBGMSG("[readerThread: waiting]");
 
613
                
 
614
                ioThreadWaitToRun(&audioIn);
 
615
                
 
616
                if (audioIn.exit) break;
 
617
                if (!audioIn.open || audioIn.stall) continue;
 
618
 
 
619
                DBGMSG("[readerThread: running]");
 
620
                
 
621
                for (;;) {
 
622
                        if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
623
                        
 
624
                        /* NB: PA Simple API does not return number of bytes/samples recorded */
 
625
                        /*   (so have to assume full buffer everytime (poss padded if less than requested) */
 
626
                        
 
627
/*                      rc = snd_pcm_readi(audioIn.alsaHandle, audioIn.alsaBuffer, audioIn.alsaFrames);
 
628
*/                      
 
629
                        if (pa_simple_read(audioIn.pa_conn, (char *)(audioIn.buffer[audioIn.bufferFree].buffer), audioIn.maxBytes, &rc) < 0) {
 
630
                                fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(rc));
 
631
                                continue;
 
632
                        }
 
633
 
 
634
                        if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
635
                        
 
636
                        /* PA: Assume max buffer frames returned... */
 
637
                        rc = audioIn.maxSamples;
 
638
                        
 
639
                        /* EPIPE means overrun */
 
640
/*                      
 
641
                        if (rc == -EPIPE) {
 
642
                                printf("readerThread: overrun occurred\n");
 
643
                                snd_pcm_prepare(audioIn.alsaHandle);
 
644
                                continue;
 
645
                        } 
 
646
                        
 
647
                        if (rc < 0) {
 
648
                                printf("readerThread: error from read: %s\n", snd_strerror(rc));
 
649
                                continue;
 
650
                        } 
 
651
                        
 
652
                        if (rc != (int)audioIn.alsaFrames) {
 
653
                                printf("readerThread: short read, read %d frames\n", rc);
 
654
                                continue;
 
655
                        }
 
656
*/                      
 
657
                        if (!audioIn.buffer[audioIn.bufferFree].isFree) {
 
658
                                printf("readerThread: No free buffers!\n");
 
659
                                continue;
 
660
                        }
 
661
                                                
 
662
                        if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
663
 
 
664
                        /* PA: Complete buffer should be returned so skipping check and moving guts to end of loop */
 
665
/*
 
666
                        if ((audioIn.buffer[audioIn.bufferFree].samples + rc) > audioIn.maxSamples) {
 
667
                                ioNextRecordBuffer();
 
668
                                if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
669
                                signalSqueak(&audioIn);
 
670
                        }
 
671
*/
 
672
 
 
673
/* Next won't get called anyway because of "stall" in ioNextRecordBuffer() */
 
674
/* Left here in case needed for debugging */
 
675
/*
 
676
                        if (!audioIn.buffer[audioIn.bufferFree].isFree) {
 
677
                                printf("readerThread: No free buffers!\n");
 
678
                                continue;
 
679
                        }
 
680
*/
 
681
                                
 
682
                        /* PA: Endian swap may not be needed... */
 
683
 
 
684
                        /* Endian Swap (rc = frames = Word Count in this case) */
 
685
/*                      
 
686
                        p = (unsigned short *)(audioIn.buffer[audioIn.bufferFree].buffer);
 
687
                        wc = rc;
 
688
                        while (wc--)
 
689
                                *p = _swapw(*p);
 
690
*/
 
691
        
 
692
                        /* PA: No copy required since record buffer used directly... */
 
693
/*      
 
694
                        memcpy((char *)(audioIn.buffer[audioIn.bufferFree].buffer) + 2 * audioIn.buffer[audioIn.bufferFree].samples, audioIn.alsaBuffer, rc*2);
 
695
                        audioIn.buffer[audioIn.bufferFree].samples += rc;
 
696
*/
 
697
                        
 
698
                        /* PA: No indication of actual bytes/samples read so assuming full buffer read (or padded)... */
 
699
                        audioIn.buffer[audioIn.bufferFree].samples = audioIn.maxSamples;
 
700
                        
 
701
                        if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
702
                
 
703
                        /* PA: These three lines moved from above (since assuming full buffers are read every time) */
 
704
                        ioNextRecordBuffer();
 
705
                        if (!audioIn.open || audioIn.stall || audioIn.exit) break;
 
706
                        signalSqueak(&audioIn);
 
707
                        
 
708
                }
 
709
                if (audioIn.exit) break;
 
710
        }
 
711
DBGMSG("[readerThread: stopped]");
 
712
}
 
713
 
 
714
 
 
715
/* ================================== IO INIT */
 
716
 
 
717
static int ioInit() {
 
718
        if (initDone) return true;
 
719
        initDone = true; 
 
720
        
 
721
        /* AUDIO OUT */
 
722
        
 
723
/* NOT USED >>> */
 
724
        audioOut.dbgName = "play";
 
725
        audioOut.device = "pa-simple"; 
 
726
/* <<< */
 
727
 
 
728
        audioOut.open = false;
 
729
        
 
730
        audioOut.maxSamples     = 0;
 
731
        audioOut.maxWords               = 0;
 
732
        audioOut.maxBytes               = 0;
 
733
        
 
734
        audioOut.maxBuffers             = MAX_OUTPUT_BUFFERS;
 
735
        audioOut.buffer                         = oBuffer;
 
736
        audioOut.bufferFree             = 0;
 
737
        audioOut.bufferNext             = 0;
 
738
        audioOut.bufferCount    = audioOut.maxBuffers;
 
739
        audioOut.bufferFull             = 0;
 
740
        audioOut.bufferMutex    = &audioOutBufferMutex;
 
741
        audioOut.buffersAllocated = false;
 
742
        
 
743
        audioOut.threadFunc = writerThread;
 
744
        audioOut.thread                 = 0;
 
745
 
 
746
        audioOut.sigRun.mutex   = &audioOutRunMutex;
 
747
        audioOut.sigRun.cond    = &audioOutRunCond;
 
748
        sigReset(&audioOut.sigRun);
 
749
        
 
750
        audioOut.sigStalled.mutex = &audioOutStalledMutex;
 
751
        audioOut.sigStalled.cond  = &audioOutStalledCond;
 
752
        sigReset(&audioOut.sigStalled);
 
753
        
 
754
        audioOut.running        = 0;
 
755
        audioOut.exit                   = 0;
 
756
        audioOut.stall          = 0;
 
757
        
 
758
        audioOut.sqSemaphore = 0;
 
759
        
 
760
        audioOut.rateID = 0;
 
761
        audioOut.bytesPerFrame = 4; /* Stereo S16LE */
 
762
 
 
763
        audioOut.pa_conn = null;
 
764
        
 
765
        ioThreadStart(&audioOut);
 
766
        
 
767
        /* AUDIO IN */
 
768
        
 
769
        audioIn.dbgName = "rec";
 
770
        
 
771
/* NOT USED >>> */
 
772
        audioIn.device = "pa-simple"; 
 
773
/* <<< */
 
774
        
 
775
        audioIn.open = false;
 
776
        
 
777
        audioIn.maxSamples      = 0;
 
778
        audioIn.maxWords                = 0;
 
779
        audioIn.maxBytes                = 0;
 
780
        
 
781
        audioIn.maxBuffers      = MAX_INPUT_BUFFERS;
 
782
        audioIn.buffer                  = iBuffer;
 
783
        audioIn.bufferFree      = 0;
 
784
        audioIn.bufferNext      = 0;
 
785
        audioIn.bufferCount     = 0; /* No buffers yet. Was audioIn.maxBuffers; */
 
786
        audioIn.bufferFull      = 0;
 
787
        audioIn.bufferMutex     = &audioInBufferMutex;
 
788
        audioIn.buffersAllocated = false;
 
789
        
 
790
        audioIn.threadFunc= readerThread;
 
791
        audioIn.thread          = 0;
 
792
        
 
793
        audioIn.sigRun.mutex                    = &audioInRunMutex;
 
794
        audioIn.sigRun.cond                             = &audioInRunCond;
 
795
        sigReset(&audioIn.sigRun);
 
796
        
 
797
        audioIn.sigStalled.mutex        = &audioInStalledMutex;
 
798
        audioIn.sigStalled.cond         = &audioInStalledCond;
 
799
        sigReset(&audioIn.sigStalled);
 
800
        
 
801
        audioIn.running = 0;
 
802
        audioIn.exit            = 0;
 
803
        audioIn.stall           = 0;
 
804
        
 
805
        audioIn.sqSemaphore     = 0;
 
806
        
 
807
        audioIn.rateID = 0;
 
808
        audioIn.bytesPerFrame = 2; /* Mono S16LE */
 
809
        
 
810
        audioIn.pa_conn = null;
 
811
        
 
812
        ioThreadStart(&audioIn);
 
813
}
 
814
 
 
815
/* ============================================ */
 
816
/* ================================== VM PLUGIN */
 
817
/* ============================================ */
 
818
 
 
819
static int trace() {
 
820
}
 
821
 
 
822
/* ================================== AUDIO OUT */
 
823
 
 
824
static sqInt sound_AvailableSpace(void) {
 
825
        return ioFreeBytes(&audioOut);
 
826
}
 
827
 
 
828
static sqInt sound_InsertSamplesFromLeadTime(int frameCount, int srcBufPtr, int samplesOfLeadTime) {
 
829
DBGMSG(">sound_InsertSamplesFromLeadTime()");
 
830
        return 0; /* or maxBytes? */
 
831
}
 
832
 
 
833
 
 
834
static sqInt sound_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex) {
 
835
        unsigned int bufferNext, samples, sampleBytes;
 
836
 
 
837
        if (0 >= frameCount) return 0;
 
838
        
 
839
        samples = MIN(audioOut.maxSamples, frameCount);
 
840
        
 
841
        if (0 == (sampleBytes = ioAddPlayBuffer((void *)(arrayIndex + startIndex * 2 * audioOut.pa_spec.channels), samples)))
 
842
                DBGMSG("sound_PlaySamplesFromAtLength(): No free buffers!");
 
843
        
 
844
        sigSignal(&audioOut.sigRun);
 
845
        
 
846
        return samples;
 
847
}
 
848
 
 
849
static sqInt sound_PlaySilence(void) {
 
850
DBGMSG(">sound_PlaySilence()");
 
851
        ioThreadStall(&audioOut);
 
852
        return 0; /* or maxBytes? */
 
853
}
 
854
 
 
855
 
 
856
static sqInt sound_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex) {
 
857
        int rc;
 
858
        
 
859
DBGMSG(">sound_Start()");
 
860
 
 
861
#ifdef DBG
 
862
printf("\tframeCount: %d, samplesPerSec: %d, stereo: %d, semaIndex: %d\n", frameCount, samplesPerSec, stereo, semaIndex);
 
863
#endif
 
864
 
 
865
        if (audioOut.open) return true;
 
866
        
 
867
  audioOut.pa_spec.format = PA_SAMPLE_S16LE;
 
868
  audioOut.pa_spec.rate = samplesPerSec; /* rate(SAMPLE_RATE_22_05KHZ) for Squeak */
 
869
  audioOut.pa_spec.channels = stereo ? 2 : 1;
 
870
  audioOut.pa_conn = NULL;
 
871
 
 
872
        /* Create a new playback stream */
 
873
        if (!(audioOut.pa_conn = pa_simple_new(NULL, "Scratch", PA_STREAM_PLAYBACK, NULL, "playback", &audioOut.pa_spec, NULL, NULL, &rc))) {
 
874
                        fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(rc));
 
875
                        success(false);
 
876
                        return false;
 
877
        }
 
878
  
 
879
        ioAllocBuffers(&audioOut, frameCount);
 
880
        audioOut.bufferCount = audioOut.maxBuffers; /* Has to be reset everytime */
 
881
        
 
882
        audioOut.sqSemaphore = semaIndex;
 
883
 
 
884
        audioOut.open = true;
 
885
        
 
886
        sigSignal(&audioOut.sigRun);
 
887
        
 
888
        /* error possibly left over from dsp-protocol.c code */
 
889
        /* dsp-protocol.c in current ALSA not capturing EINTR/EAGAIN */
 
890
        /* EINTR/EAGAIN from dsp-protocol.c not raised up to ALSA so not caught by ALSA */
 
891
        /* Clearing errno here to see if Squeak can continue regardless */
 
892
        errno = 0; 
 
893
        
 
894
DBGMSG("<sound_Start()");
 
895
        return true;
 
896
}
 
897
 
 
898
 
 
899
static sqInt sound_Stop(void) {
 
900
        int rc;
 
901
        
 
902
DBGMSG(">sound_Stop()");
 
903
 
 
904
        if (!audioOut.open) return true;
 
905
        audioOut.open = false;
 
906
        
 
907
        if (NULL == audioOut.pa_conn) return true;
 
908
        
 
909
        ioThreadStall(&audioOut);
 
910
 
 
911
        if (pa_simple_drain(audioOut.pa_conn, &rc) < 0) {
 
912
                fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(rc));
 
913
        }
 
914
 
 
915
  if (NULL != audioOut.pa_conn)
 
916
     pa_simple_free(audioOut.pa_conn);
 
917
        
 
918
        ioFreeBuffers(&audioOut);
 
919
 
 
920
        audioOut.pa_conn = NULL;
 
921
        audioOut.sqSemaphore = 0;
 
922
 
 
923
DBGMSG("<sound_Stop()");
 
924
        return true;
 
925
}
 
926
 
 
927
 
 
928
 
 
929
/* ================================== AUDIO IN */
 
930
 
 
931
static sqInt sound_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex) {
 
932
        int rc;
 
933
        pa_buffer_attr pa_buffer_metrics; /* For recording */
 
934
 
 
935
DBGMSG(">sound_StartRecording()");
 
936
 
 
937
        if (audioIn.open) return true;
 
938
        
 
939
        audioIn.pa_spec.format = PA_SAMPLE_S16LE;
 
940
        audioIn.pa_spec.rate = desiredSamplesPerSec;
 
941
        audioIn.pa_spec.channels = stereo ? 2 : 1;
 
942
        audioIn.pa_conn = NULL;
 
943
    
 
944
        pa_buffer_metrics.maxlength     = (uint32_t) -1;
 
945
        pa_buffer_metrics.tlength       = (uint32_t) -1; /* playback only */
 
946
        pa_buffer_metrics.prebuf        = (uint32_t) -1; /* playback only */ 
 
947
        pa_buffer_metrics.minreq        = (uint32_t) -1; /* playback only */
 
948
        pa_buffer_metrics.fragsize      = pa_usec_to_bytes(20*1000, &audioIn.pa_spec); 
 
949
 
 
950
        /* Create the recording stream */
 
951
        if (!(audioIn.pa_conn = pa_simple_new(  NULL, 
 
952
                                                                                        "Scratch", 
 
953
                                                                                        PA_STREAM_RECORD, 
 
954
                                                                                        NULL, 
 
955
                                                                                        "record", 
 
956
                                                                                        &audioIn.pa_spec, 
 
957
                                                                                        NULL, 
 
958
                                                                                        &pa_buffer_metrics, 
 
959
                                                                                        &rc)))
 
960
        {
 
961
                        fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(rc));
 
962
                        success(false);
 
963
                        return false;
 
964
        }
 
965
 
 
966
  /* Only rate supported on the N810 (atm) is 8000 */
 
967
/*  
 
968
  audioIn.alsaRate = 8000; 
 
969
*/
 
970
  
 
971
  /* 20Hz update freq for Squeak sounds reasonable, so... */
 
972
  audioIn.maxSamples = audioIn.pa_spec.rate / 20;
 
973
        
 
974
  /* Use a buffer large enough to hold one period (assuming 2 bytes/sample) */
 
975
/*  
 
976
  audioIn.alsaBufferSize = audioIn.maxSamples * 2 * audioIn.pa_spec.channels; 
 
977
  audioIn.alsaBuffer = (char *) malloc(audioIn.alsaBufferSize);
 
978
*/
 
979
 
 
980
        /* Buffers will be filled before signalling Squeak. So rate & buffer size determined signalling freq... */
 
981
        ioAllocBuffers(&audioIn, audioIn.pa_spec.rate / 20 ); /* for Sq signalling rate of 20Hz */
 
982
        audioIn.bufferCount     = 0; /* Has to be reset everytime */
 
983
 
 
984
        audioIn.sqSemaphore = semaIndex;
 
985
        
 
986
        audioIn.open = true;
 
987
        
 
988
        sigSignal(&audioIn.sigRun);
 
989
                
 
990
DBGMSG("<sound_StartRecording()");
 
991
        return true;
 
992
}
 
993
 
 
994
static sqInt sound_StopRecording(void) {
 
995
DBGMSG(">sound_StopRecording()");
 
996
 
 
997
        if (!audioIn.open) return;
 
998
        audioIn.open = false;
 
999
        
 
1000
        if (NULL == audioIn.pa_conn) return;
 
1001
        
 
1002
        ioThreadStall(&audioIn);
 
1003
 
 
1004
  pa_simple_free(audioIn.pa_conn);
 
1005
  
 
1006
        ioFreeBuffers(&audioIn);
 
1007
        
 
1008
        audioIn.pa_conn = NULL;
 
1009
        
 
1010
        audioIn.sqSemaphore = 0;
 
1011
 
 
1012
DBGMSG("<sound_StopRecording()");
 
1013
        return true;
 
1014
}
 
1015
 
 
1016
static double sound_GetRecordingSampleRate(void) {
 
1017
        return (double)audioIn.pa_spec.rate;
 
1018
}
 
1019
 
 
1020
static sqInt sound_RecordSamplesIntoAtLength(int buf, int startSliceIndex, int bufferSizeInBytes) {
 
1021
        unsigned int bufferNext, bufferBytes, sampleBytes;
 
1022
 
 
1023
        bufferBytes = MAX(0, bufferSizeInBytes - (startSliceIndex * 2));
 
1024
        if (0 == bufferBytes) {
 
1025
                printf("***(%d) sound_RecordSamplesIntoAtLength(): No space in Squeak buffer!\n", startSliceIndex);
 
1026
                return 0;
 
1027
        }
 
1028
        
 
1029
        /* DMOC 090909 1800: Hmmmm, what if Squeak does not read whole buffer? ATM remaining buffer data lost since */
 
1030
        /*   ioGetRecordBuffer() frees the buffer after single visit. Needs more work */
 
1031
        
 
1032
        bufferNext = audioIn.bufferNext; /* preserved for debug output */
 
1033
        sampleBytes = ioGetRecordBuffer((void *)(buf + (startSliceIndex * 2)), bufferBytes);
 
1034
/*
 
1035
        if (0 < sampleBytes)
 
1036
                printf("   sound_RecordSamplesIntoAtLength(%d, %d, %d) %d, %d\n", buf, startSliceIndex, bufferSizeInBytes, bufferNext, sampleBytes);
 
1037
        else
 
1038
                printf("***sound_RecordSamplesIntoAtLength(%d, %d, %d) %d, %d\n", buf, startSliceIndex, bufferSizeInBytes, bufferNext, sampleBytes);
 
1039
*/      
 
1040
        return MAX(0, sampleBytes)/(2 * audioIn.pa_spec.channels);
 
1041
}
 
1042
 
 
1043
 
 
1044
/* ================================== sound mixer */
 
1045
 
 
1046
/*
 
1047
static int     sound_nomixer  = 0;
 
1048
static snd_mixer_t  *mixer_handle = 0;
 
1049
static snd_mixer_elem_t *mixer_element  = 0;
 
1050
*/
 
1051
 
 
1052
static int mixer_open(char *name) {
 
1053
  trace();
 
1054
  return -EACCES;
 
1055
}
 
1056
 
 
1057
static void mixer_close(void) {
 
1058
  trace();
 
1059
}
 
1060
 
 
1061
static inline void mixer_getVolume(char *name, int captureFlag, double *leftLevel, double *rightLevel) {
 
1062
  trace();
 
1063
}
 
1064
 
 
1065
static inline void mixer_setVolume(char *name, int captureFlag, double leftLevel, double rightLevel) {
 
1066
  trace();
 
1067
}
 
1068
 
 
1069
static int mixer_setSwitch(char *name, int captureFlag, int parameter) {
 
1070
  trace();
 
1071
  return 0;
 
1072
}
 
1073
 
 
1074
static int mixer_getSwitch(char *name, int captureFlag, int channel) {
 
1075
  trace();
 
1076
  return -1;
 
1077
}
 
1078
 
 
1079
static void sound_Volume(double *left, double *right) {
 
1080
  trace();
 
1081
  *left= 1.0;
 
1082
  *right= 1.0;
 
1083
}
 
1084
 
 
1085
static void sound_SetVolume(double left, double right) {
 
1086
  trace();
 
1087
}
 
1088
 
 
1089
static sqInt sound_SetRecordLevel(sqInt level) {
 
1090
  trace();
 
1091
  return 1;
 
1092
  return level;
 
1093
}
 
1094
 
 
1095
static sqInt sound_SetDevice(sqInt id, char *arg) {
 
1096
  trace();
 
1097
  return -1;
 
1098
}
 
1099
 
 
1100
static sqInt sound_GetSwitch(sqInt id, sqInt captureFlag, sqInt channel) {
 
1101
  trace();
 
1102
  return -1;
 
1103
}
 
1104
 
 
1105
static sqInt sound_SetSwitch(sqInt id, sqInt captureFlag, sqInt parameter) {
 
1106
  trace();
 
1107
  return -1;
 
1108
}
 
1109
 
 
1110
 
 
1111
/* module */
 
1112
 
 
1113
#include "SqSound.h"
 
1114
 
 
1115
SqSoundDefine(PA);
 
1116
 
 
1117
#include "SqModule.h"
 
1118
 
 
1119
static void sound_parseEnvironment(void) {
 
1120
/*
 
1121
  char *ev= 0;
 
1122
 
 
1123
  sound_SetDevice(0, NULL);
 
1124
  sound_SetDevice(1, NULL);
 
1125
  sound_SetDevice(2, NULL);
 
1126
 
 
1127
  if (     getenv("SQUEAK_NOMIXER"   )) sound_nomixer= 1;
 
1128
  if ((ev= getenv("SQUEAK_SOUNDCARD"))) sound_SetDevice(0, ev);
 
1129
  if ((ev= getenv("SQUEAK_PLAYBACK" ))) sound_SetDevice(1, ev);
 
1130
  if ((ev= getenv("SQUEAK_CAPTURE"  ))) sound_SetDevice(2, ev);
 
1131
*/
 
1132
}
 
1133
 
 
1134
static int sound_parseArgument(int argc, char **argv) {
 
1135
/*
 
1136
  if     (!strcmp(argv[0], "-nomixer"  )) { sound_nomixer= 1;   return 1; }
 
1137
  else if (argv[1])
 
1138
    {
 
1139
      if (!strcmp(argv[0], "-soundcard")) { sound_SetDevice(0, argv[1]);  return 2; }
 
1140
      if (!strcmp(argv[0], "-playback" )) { sound_SetDevice(1, argv[1]);  return 2; }
 
1141
      if (!strcmp(argv[0], "-capture"  )) { sound_SetDevice(2, argv[1]);  return 2; }
 
1142
    }
 
1143
*/
 
1144
  return 0;
 
1145
}
 
1146
 
 
1147
static void  sound_printUsage(void) {
 
1148
  printf("\nPulseAudio <option>s: <none>\n");
 
1149
/*
 
1150
  printf("  -nomixer              disable mixer (volume) adjustment\n");
 
1151
  printf("  -soundcard <name>     open the named sound card (default: %s)\n", sound_device);
 
1152
  printf("  -playback <name>      play to the named sound device (default: %s)\n", sound_playback);
 
1153
  printf("  -capture <name>       record from the named sound device (default: %s)\n", sound_capture);
 
1154
*/
 
1155
}
 
1156
 
 
1157
static void  sound_printUsageNotes(void) {
 
1158
}
 
1159
 
 
1160
static void *sound_makeInterface(void) {
 
1161
/*#ifdef NEWSIG
 
1162
//  sigalrm_save(); // DMOC: Being here assumes old handler same for run duration! Same for sigio handler.
 
1163
//#else
 
1164
// DMOC: Rethink: Signal captured once, preserved and restored when/where necessary?
 
1165
//  sigio_save();
 
1166
//#endif
 
1167
*/
 
1168
        
 
1169
#ifdef USE_RESOURCE_MANAGER
 
1170
printf("USE_RESOURCE_MANAGER\n");
 
1171
#endif
 
1172
        
 
1173
        ioInit();
 
1174
        
 
1175
  return &sound_PA_itf;
 
1176
}
 
1177
 
 
1178
SqModuleDefine(sound, pulse);