To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / oss / pa_unix_oss.c @ 162:d43aab368df9

History | View | Annotate | Download (69.7 KB)

1
/*
2
 * $Id$
3
 * PortAudio Portable Real-Time Audio Library
4
 * Latest Version at: http://www.portaudio.com
5
 * OSS implementation by:
6
 *   Douglas Repetto
7
 *   Phil Burk
8
 *   Dominic Mazzoni
9
 *   Arve Knudsen
10
 *
11
 * Based on the Open Source API proposed by Ross Bencina
12
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
13
 *
14
 * Permission is hereby granted, free of charge, to any person obtaining
15
 * a copy of this software and associated documentation files
16
 * (the "Software"), to deal in the Software without restriction,
17
 * including without limitation the rights to use, copy, modify, merge,
18
 * publish, distribute, sublicense, and/or sell copies of the Software,
19
 * and to permit persons to whom the Software is furnished to do so,
20
 * subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be
23
 * included in all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
29
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
30
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
 */
33

    
34
/*
35
 * The text above constitutes the entire PortAudio license; however,
36
 * the PortAudio community also makes the following non-binding requests:
37
 *
38
 * Any person wishing to distribute modifications to the Software is
39
 * requested to send the modifications to the original developer so that
40
 * they can be incorporated into the canonical version. It is also
41
 * requested that these non-binding requests be included along with the
42
 * license above.
43
 */
44

    
45
/**
46
 @file
47
 @ingroup hostapi_src
48
*/
49

    
50
#include <stdio.h>
51
#include <string.h>
52
#include <math.h>
53
#include <fcntl.h>
54
#include <sys/ioctl.h>
55
#include <unistd.h>
56
#include <pthread.h>
57
#include <stdlib.h>
58
#include <assert.h>
59
#include <errno.h>
60
#include <sys/types.h>
61
#include <sys/stat.h>
62
#include <sys/poll.h>
63
#include <limits.h>
64
#include <semaphore.h>
65

    
66
#ifdef HAVE_SYS_SOUNDCARD_H
67
# include <sys/soundcard.h>
68
# ifdef __NetBSD__
69
#  define DEVICE_NAME_BASE           "/dev/audio"
70
# else
71
#  define DEVICE_NAME_BASE           "/dev/dsp"
72
# endif
73
#elif defined(HAVE_LINUX_SOUNDCARD_H)
74
# include <linux/soundcard.h>
75
# define DEVICE_NAME_BASE            "/dev/dsp"
76
#elif defined(HAVE_MACHINE_SOUNDCARD_H)
77
# include <machine/soundcard.h> /* JH20010905 */
78
# define DEVICE_NAME_BASE            "/dev/audio"
79
#else
80
# error No sound card header file
81
#endif
82

    
83
#include "portaudio.h"
84
#include "pa_util.h"
85
#include "pa_allocation.h"
86
#include "pa_hostapi.h"
87
#include "pa_stream.h"
88
#include "pa_cpuload.h"
89
#include "pa_process.h"
90
#include "pa_unix_util.h"
91
#include "pa_debugprint.h"
92

    
93
static int sysErr_;
94
static pthread_t mainThread_;
95

    
96
/* Check return value of system call, and map it to PaError */
97
#define ENSURE_(expr, code) \
98
    do { \
99
        if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \
100
        { \
101
            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
102
            if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
103
            { \
104
                PaUtil_SetLastHostErrorInfo( paOSS, sysErr_, strerror( errno ) ); \
105
            } \
106
            \
107
            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
108
            result = (code); \
109
            goto error; \
110
        } \
111
    } while( 0 );
112

    
113
#ifndef AFMT_S16_NE
114
#define AFMT_S16_NE  Get_AFMT_S16_NE()
115
/*********************************************************************
116
 * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
117
 * PowerPC is Big Endian. X86 is Little Endian.
118
 */
119
static int Get_AFMT_S16_NE( void )
120
{
121
    long testData = 1;
122
    char *ptr = (char *) &testData;
123
    int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
124
    return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
125
}
126
#endif
127

    
128
/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
129

    
130
typedef struct
131
{
132
    PaUtilHostApiRepresentation inheritedHostApiRep;
133
    PaUtilStreamInterface callbackStreamInterface;
134
    PaUtilStreamInterface blockingStreamInterface;
135

    
136
    PaUtilAllocationGroup *allocations;
137

    
138
    PaHostApiIndex hostApiIndex;
139
}
140
PaOSSHostApiRepresentation;
141

    
142
/** Per-direction structure for PaOssStream.
143
 *
144
 * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback,
145
 * but with different number of channels we will have to adapt between the number of user and host
146
 * channels for at least one direction, since the configuration space is the same for both directions
147
 * of an OSS device.
148
 */
149
typedef struct
150
{
151
    int fd;
152
    const char *devName;
153
    int userChannelCount, hostChannelCount;
154
    int userInterleaved;
155
    void *buffer;
156
    PaSampleFormat userFormat, hostFormat;
157
    double latency;
158
    unsigned long hostFrames, numBufs;
159
    void **userBuffers; /* For non-interleaved blocking */
160
} PaOssStreamComponent;
161

    
162
/** Implementation specific representation of a PaStream.
163
 *
164
 */
165
typedef struct PaOssStream
166
{
167
    PaUtilStreamRepresentation streamRepresentation;
168
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
169
    PaUtilBufferProcessor bufferProcessor;
170

    
171
    PaUtilThreading threading;
172

    
173
    int sharedDevice;
174
    unsigned long framesPerHostBuffer;
175
    int triggered;  /* Have the devices been triggered yet (first start) */
176

    
177
    int isActive;
178
    int isStopped;
179

    
180
    int lastPosPtr;
181
    double lastStreamBytes;
182

    
183
    int framesProcessed;
184

    
185
    double sampleRate;
186

    
187
    int callbackMode;
188
    volatile int callbackStop, callbackAbort;
189

    
190
    PaOssStreamComponent *capture, *playback;
191
    unsigned long pollTimeout;
192
    sem_t semaphore;
193
}
194
PaOssStream;
195

    
196
typedef enum {
197
    StreamMode_In,
198
    StreamMode_Out
199
} StreamMode;
200

    
201
/* prototypes for functions declared in this file */
202

    
203
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
204
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
205
                                  const PaStreamParameters *inputParameters,
206
                                  const PaStreamParameters *outputParameters,
207
                                  double sampleRate );
208
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
209
                           PaStream** s,
210
                           const PaStreamParameters *inputParameters,
211
                           const PaStreamParameters *outputParameters,
212
                           double sampleRate,
213
                           unsigned long framesPerBuffer,
214
                           PaStreamFlags streamFlags,
215
                           PaStreamCallback *streamCallback,
216
                           void *userData );
217
static PaError CloseStream( PaStream* stream );
218
static PaError StartStream( PaStream *stream );
219
static PaError StopStream( PaStream *stream );
220
static PaError AbortStream( PaStream *stream );
221
static PaError IsStreamStopped( PaStream *s );
222
static PaError IsStreamActive( PaStream *stream );
223
static PaTime GetStreamTime( PaStream *stream );
224
static double GetStreamCpuLoad( PaStream* stream );
225
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
226
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
227
static signed long GetStreamReadAvailable( PaStream* stream );
228
static signed long GetStreamWriteAvailable( PaStream* stream );
229
static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
230

    
231

    
232
/** Initialize the OSS API implementation.
233
 *
234
 * This function will initialize host API datastructures and query host devices for information.
235
 *
236
 * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here
237
 *
238
 * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function,
239
 * this happens with the usual "error" label.
240
 */
241
PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
242
{
243
    PaError result = paNoError;
244
    PaOSSHostApiRepresentation *ossHostApi = NULL;
245

    
246
    PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),
247
            paInsufficientMemory );
248
    PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
249
    ossHostApi->hostApiIndex = hostApiIndex;
250

    
251
    /* Initialize host API structure */
252
    *hostApi = &ossHostApi->inheritedHostApiRep;
253
    (*hostApi)->info.structVersion = 1;
254
    (*hostApi)->info.type = paOSS;
255
    (*hostApi)->info.name = "OSS";
256
    (*hostApi)->Terminate = Terminate;
257
    (*hostApi)->OpenStream = OpenStream;
258
    (*hostApi)->IsFormatSupported = IsFormatSupported;
259

    
260
    PA_ENSURE( BuildDeviceList( ossHostApi ) );
261

    
262
    PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
263
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
264
                                      GetStreamTime, GetStreamCpuLoad,
265
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
266
                                      PaUtil_DummyGetReadAvailable,
267
                                      PaUtil_DummyGetWriteAvailable );
268

    
269
    PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
270
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
271
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
272
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
273

    
274
    mainThread_ = pthread_self();
275

    
276
    return result;
277

    
278
error:
279
    if( ossHostApi )
280
    {
281
        if( ossHostApi->allocations )
282
        {
283
            PaUtil_FreeAllAllocations( ossHostApi->allocations );
284
            PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
285
        }
286

    
287
        PaUtil_FreeMemory( ossHostApi );
288
    }
289
    return result;
290
}
291

    
292
PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,
293
        int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,
294
        PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations  )
295
{
296
    PaError result = paNoError;
297

    
298
    deviceInfo->structVersion = 2;
299
    if( allocations )
300
    {
301
        size_t len = strlen( name ) + 1;
302
        PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );
303
        strncpy( (char *)deviceInfo->name, name, len );
304
    }
305
    else
306
        deviceInfo->name = name;
307

    
308
    deviceInfo->hostApi = hostApiIndex;
309
    deviceInfo->maxInputChannels = maxInputChannels;
310
    deviceInfo->maxOutputChannels = maxOutputChannels;
311
    deviceInfo->defaultLowInputLatency = defaultLowInputLatency;
312
    deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;
313
    deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
314
    deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
315
    deviceInfo->defaultSampleRate = defaultSampleRate;
316

    
317
error:
318
    return result;
319
}
320

    
321
static int CalcHigherLogTwo( int n )
322
{
323
    int log2 = 0;
324
    while( (1<<log2) < n ) log2++;
325
    return log2;
326
}
327

    
328
static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
329
        double *defaultLowLatency, double *defaultHighLatency )
330
{
331
    PaError result = paNoError;
332
    int numChannels, maxNumChannels;
333
    int busy = 0;
334
    int devHandle = -1;
335
    int sr;
336
    *maxChannelCount = 0;  /* Default value in case this fails */
337
    int temp, frgmt;
338
    unsigned long fragFrames;
339

    
340
    if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK ))  < 0 )
341
    {
342
        if( errno == EBUSY || errno == EAGAIN )
343
        {
344
            PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));
345
        }
346
        else
347
        {
348
            /* Ignore ENOENT, which means we've tried a non-existent device */
349
            if( errno != ENOENT )
350
            {
351
                PA_DEBUG(( "%s: Can't access device %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
352
            }
353
        }
354

    
355
        return paDeviceUnavailable;
356
    }
357

    
358
    /* Negotiate for the maximum number of channels for this device. PLB20010927
359
     * Consider up to 16 as the upper number of channels.
360
     * Variable maxNumChannels should contain the actual upper limit after the call.
361
     * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
362
     */
363
    maxNumChannels = 0;
364
    for( numChannels = 1; numChannels <= 16; numChannels++ )
365
    {
366
        temp = numChannels;
367
        if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
368
        {
369
            busy = EAGAIN == errno || EBUSY == errno;
370
            /* ioctl() failed so bail out if we already have stereo */
371
            if( maxNumChannels >= 2 )
372
                break;
373
        }
374
        else
375
        {
376
            /* ioctl() worked but bail out if it does not support numChannels.
377
             * We don't want to leave gaps in the numChannels supported.
378
             */
379
            if( (numChannels > 2) && (temp != numChannels) )
380
                break;
381
            if( temp > maxNumChannels )
382
                maxNumChannels = temp; /* Save maximum. */
383
        }
384
    }
385
    /* A: We're able to open a device for capture if it's busy playing back and vice versa,
386
     * but we can't configure anything */
387
    if( 0 == maxNumChannels && busy )
388
    {
389
        result = paDeviceUnavailable;
390
        goto error;
391
    }
392

    
393
    /* The above negotiation may fail for an old driver so try this older technique. */
394
    if( maxNumChannels < 1 )
395
    {
396
        int stereo = 1;
397
        if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 )
398
        {
399
            maxNumChannels = 1;
400
        }
401
        else
402
        {
403
            maxNumChannels = (stereo) ? 2 : 1;
404
        }
405
        PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ));
406
    }
407

    
408
    /* During channel negotiation, the last ioctl() may have failed. This can
409
     * also cause sample rate negotiation to fail. Hence the following, to return
410
     * to a supported number of channels. SG20011005 */
411
    {
412
        /* use most reasonable default value */
413
        numChannels = PA_MIN( maxNumChannels, 2 );
414
        ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &numChannels ), paUnanticipatedHostError );
415
    }
416

    
417
    /* Get supported sample rate closest to 44100 Hz */
418
    if( *defaultSampleRate < 0 )
419
    {
420
        sr = 44100;
421
        ENSURE_( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ), paUnanticipatedHostError );
422

    
423
        *defaultSampleRate = sr;
424
    }
425

    
426
    *maxChannelCount = maxNumChannels;
427

    
428
    /* Attempt to set low latency with 4 frags-per-buffer, 128 frames-per-frag (total buffer 512 frames)
429
     * since the ioctl sets bytes, multiply by numChannels, and base on 2 bytes-per-sample, */
430
    fragFrames = 128;
431
    frgmt = (4 << 16) + (CalcHigherLogTwo( fragFrames * numChannels * 2 ) & 0xffff);
432
    ENSURE_( ioctl( devHandle, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
433

    
434
    /* Use the value set by the ioctl to give the latency achieved */
435
    fragFrames = pow( 2, frgmt & 0xffff ) / (numChannels * 2);
436
    *defaultLowLatency = ((frgmt >> 16) - 1) * fragFrames / *defaultSampleRate;
437

    
438
    /* Cannot now try setting a high latency (device would need closing and opening again).  Make
439
     * high-latency 4 times the low unless the fragFrames are significantly more than requested 128 */
440
    temp = (fragFrames < 256) ? 4 : (fragFrames < 512) ? 2 : 1;
441
    *defaultHighLatency = temp * *defaultLowLatency;
442

    
443
error:
444
    if( devHandle >= 0 )
445
        close( devHandle );
446

    
447
    return result;
448
}
449

    
450
/** Query OSS device.
451
 *
452
 * This is where PaDeviceInfo objects are constructed and filled in with relevant information.
453
 *
454
 * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
455
 * in place.
456
 */
457
static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
458
{
459
    PaError result = paNoError;
460
    double sampleRate = -1.;
461
    int maxInputChannels, maxOutputChannels;
462
    PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
463
    PaError tmpRes = paNoError;
464
    int busy = 0;
465
    *deviceInfo = NULL;
466

    
467
    /* douglas:
468
       we have to do this querying in a slightly different order. apparently
469
       some sound cards will give you different info based on their settins.
470
       e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
471
       the correct order for OSS is: format, channels, sample rate
472
    */
473

    
474
    /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
475
     * opened in, it may have more channels available for capture than playback and vice versa. Therefore
476
     * we will open the device in both read- and write-only mode to determine the supported number.
477
     */
478
    if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
479
                &defaultHighInputLatency )) != paNoError )
480
    {
481
        if( tmpRes != paDeviceUnavailable )
482
        {
483
            PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
484
            /* PA_ENSURE( tmpRes ); */
485
        }
486
        ++busy;
487
    }
488
    if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
489
                &defaultHighOutputLatency )) != paNoError )
490
    {
491
        if( tmpRes != paDeviceUnavailable )
492
        {
493
            PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
494
            /* PA_ENSURE( tmpRes ); */
495
        }
496
        ++busy;
497
    }
498
    assert( 0 <= busy && busy <= 2 );
499
    if( 2 == busy )     /* Both directions are unavailable to us */
500
    {
501
        result = paDeviceUnavailable;
502
        goto error;
503
    }
504

    
505
    PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
506
    PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
507
                defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
508
                ossApi->allocations ) );
509

    
510
error:
511
    return result;
512
}
513

    
514
/** Query host devices.
515
 *
516
 * Loop over host devices and query their capabilitiesu
517
 *
518
 * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
519
 * per device, these are placed in the host api representation's deviceInfos array.
520
 */
521
static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
522
{
523
    PaError result = paNoError;
524
    PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
525
    int i;
526
    int numDevices = 0, maxDeviceInfos = 1;
527
    PaDeviceInfo **deviceInfos = NULL;
528

    
529
    /* These two will be set to the first working input and output device, respectively */
530
    commonApi->info.defaultInputDevice = paNoDevice;
531
    commonApi->info.defaultOutputDevice = paNoDevice;
532

    
533
    /* Find devices by calling QueryDevice on each
534
     * potential device names.  When we find a valid one,
535
     * add it to a linked list.
536
     * A: Set an arbitrary of 100 devices, should probably be a smarter way. */
537

    
538
    for( i = 0; i < 100; i++ )
539
    {
540
       char deviceName[32];
541
       PaDeviceInfo *deviceInfo;
542
       int testResult;
543

    
544
       if( i == 0 )
545
          snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
546
       else
547
          snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);
548

    
549
       /* PA_DEBUG(("%s: trying device %s\n", __FUNCTION__, deviceName )); */
550
       if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
551
       {
552
           if( testResult != paDeviceUnavailable )
553
               PA_ENSURE( testResult );
554

    
555
           continue;
556
       }
557

    
558
       ++numDevices;
559
       if( !deviceInfos || numDevices > maxDeviceInfos )
560
       {
561
           maxDeviceInfos *= 2;
562
           PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
563
                   paInsufficientMemory );
564
       }
565
       {
566
           int devIdx = numDevices - 1;
567
           deviceInfos[devIdx] = deviceInfo;
568

    
569
           if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
570
               commonApi->info.defaultInputDevice = devIdx;
571
           if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
572
               commonApi->info.defaultOutputDevice = devIdx;
573
       }
574
    }
575

    
576
    /* Make an array of PaDeviceInfo pointers out of the linked list */
577

    
578
    PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));
579

    
580
    commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
581
        ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
582
    memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );
583

    
584
    commonApi->info.deviceCount = numDevices;
585

    
586
error:
587
    free( deviceInfos );
588

    
589
    return result;
590
}
591

    
592
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
593
{
594
    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
595

    
596
    if( ossHostApi->allocations )
597
    {
598
        PaUtil_FreeAllAllocations( ossHostApi->allocations );
599
        PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
600
    }
601

    
602
    PaUtil_FreeMemory( ossHostApi );
603
}
604

    
605
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
606
                                  const PaStreamParameters *inputParameters,
607
                                  const PaStreamParameters *outputParameters,
608
                                  double sampleRate )
609
{
610
    PaError result = paNoError;
611
    PaDeviceIndex device;
612
    PaDeviceInfo *deviceInfo;
613
    char *deviceName;
614
    int inputChannelCount, outputChannelCount;
615
    int tempDevHandle = -1;
616
    int flags;
617
    PaSampleFormat inputSampleFormat, outputSampleFormat;
618

    
619
    if( inputParameters )
620
    {
621
        inputChannelCount = inputParameters->channelCount;
622
        inputSampleFormat = inputParameters->sampleFormat;
623

    
624
        /* unless alternate device specification is supported, reject the use of
625
            paUseHostApiSpecificDeviceSpecification */
626

    
627
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
628
            return paInvalidDevice;
629

    
630
        /* check that input device can support inputChannelCount */
631
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
632
            return paInvalidChannelCount;
633

    
634
        /* validate inputStreamInfo */
635
        if( inputParameters->hostApiSpecificStreamInfo )
636
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
637
    }
638
    else
639
    {
640
        inputChannelCount = 0;
641
    }
642

    
643
    if( outputParameters )
644
    {
645
        outputChannelCount = outputParameters->channelCount;
646
        outputSampleFormat = outputParameters->sampleFormat;
647

    
648
        /* unless alternate device specification is supported, reject the use of
649
            paUseHostApiSpecificDeviceSpecification */
650

    
651
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
652
            return paInvalidDevice;
653

    
654
        /* check that output device can support inputChannelCount */
655
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
656
            return paInvalidChannelCount;
657

    
658
        /* validate outputStreamInfo */
659
        if( outputParameters->hostApiSpecificStreamInfo )
660
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
661
    }
662
    else
663
    {
664
        outputChannelCount = 0;
665
    }
666

    
667
    if (inputChannelCount == 0 && outputChannelCount == 0)
668
        return paInvalidChannelCount;
669

    
670
    /* if full duplex, make sure that they're the same device */
671

    
672
    if (inputChannelCount > 0 && outputChannelCount > 0 &&
673
        inputParameters->device != outputParameters->device)
674
        return paInvalidDevice;
675

    
676
    /* if full duplex, also make sure that they're the same number of channels */
677

    
678
    if (inputChannelCount > 0 && outputChannelCount > 0 &&
679
        inputChannelCount != outputChannelCount)
680
       return paInvalidChannelCount;
681

    
682
    /* open the device so we can do more tests */
683

    
684
    if( inputChannelCount > 0 )
685
    {
686
        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
687
        if (result != paNoError)
688
            return result;
689
    }
690
    else
691
    {
692
        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
693
        if (result != paNoError)
694
            return result;
695
    }
696

    
697
    deviceInfo = hostApi->deviceInfos[device];
698
    deviceName = (char *)deviceInfo->name;
699

    
700
    flags = O_NONBLOCK;
701
    if (inputChannelCount > 0 && outputChannelCount > 0)
702
       flags |= O_RDWR;
703
    else if (inputChannelCount > 0)
704
       flags |= O_RDONLY;
705
    else
706
       flags |= O_WRONLY;
707

    
708
    ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );
709

    
710
    /* PaOssStream_Configure will do the rest of the checking for us */
711
    /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */
712

    
713
    /* everything succeeded! */
714

    
715
 error:
716
    if( tempDevHandle >= 0 )
717
        close( tempDevHandle );
718

    
719
    return result;
720
}
721

    
722
/** Validate stream parameters.
723
 *
724
 * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
725
 */
726
static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
727
{
728
    int maxChans;
729

    
730
    assert( parameters );
731

    
732
    if( parameters->device == paUseHostApiSpecificDeviceSpecification )
733
    {
734
        return paInvalidDevice;
735
    }
736

    
737
    maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
738
        deviceInfo->maxOutputChannels);
739
    if( parameters->channelCount > maxChans )
740
    {
741
        return paInvalidChannelCount;
742
    }
743

    
744
    return paNoError;
745
}
746

    
747
static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
748
        int callbackMode, int fd, const char *deviceName )
749
{
750
    PaError result = paNoError;
751
    assert( component );
752

    
753
    memset( component, 0, sizeof (PaOssStreamComponent) );
754

    
755
    component->fd = fd;
756
    component->devName = deviceName;
757
    component->userChannelCount = parameters->channelCount;
758
    component->userFormat = parameters->sampleFormat;
759
    component->latency = parameters->suggestedLatency;
760
    component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);
761

    
762
    if( !callbackMode && !component->userInterleaved )
763
    {
764
        /* Pre-allocate non-interleaved user provided buffers */
765
        PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
766
                paInsufficientMemory );
767
    }
768

    
769
error:
770
    return result;
771
}
772

    
773
static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
774
{
775
    assert( component );
776

    
777
    if( component->fd >= 0 )
778
        close( component->fd );
779
    if( component->buffer )
780
        PaUtil_FreeMemory( component->buffer );
781

    
782
    if( component->userBuffers )
783
        PaUtil_FreeMemory( component->userBuffers );
784

    
785
    PaUtil_FreeMemory( component );
786
}
787

    
788
static PaError ModifyBlocking( int fd, int blocking )
789
{
790
    PaError result = paNoError;
791
    int fflags;
792

    
793
    ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );
794

    
795
    if( blocking )
796
        fflags &= ~O_NONBLOCK;
797
    else
798
        fflags |= O_NONBLOCK;
799

    
800
    ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );
801

    
802
error:
803
    return result;
804
}
805

    
806
/** Open input and output devices.
807
 *
808
 * @param idev: Returned input device file descriptor.
809
 * @param odev: Returned output device file descriptor.
810
 */
811
static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )
812
{
813
    PaError result = paNoError;
814
    int flags = O_NONBLOCK, duplex = 0;
815
    *idev = *odev = -1;
816

    
817
    if( idevName && odevName )
818
    {
819
        duplex = 1;
820
        flags |= O_RDWR;
821
    }
822
    else if( idevName )
823
        flags |= O_RDONLY;
824
    else
825
        flags |= O_WRONLY;
826

    
827
    /* open first in nonblocking mode, in case it's busy...
828
     * A: then unset the non-blocking attribute */
829
    assert( flags & O_NONBLOCK );
830
    if( idevName )
831
    {
832
        ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );
833
        PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */
834
    }
835
    if( odevName )
836
    {
837
        if( !idevName )
838
        {
839
            ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );
840
            PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */
841
        }
842
        else
843
        {
844
            ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );
845
        }
846
    }
847

    
848
error:
849
    return result;
850
}
851

    
852
static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
853
        PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,
854
        PaOSSHostApiRepresentation *ossApi )
855
{
856
    PaError result = paNoError;
857
    int idev, odev;
858
    PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;
859
    const char *idevName = NULL, *odevName = NULL;
860

    
861
    assert( stream );
862

    
863
    memset( stream, 0, sizeof (PaOssStream) );
864
    stream->isStopped = 1;
865

    
866
    PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );
867

    
868
    if( inputParameters && outputParameters )
869
    {
870
        if( inputParameters->device == outputParameters->device )
871
            stream->sharedDevice = 1;
872
    }
873

    
874
    if( inputParameters )
875
        idevName = hostApi->deviceInfos[inputParameters->device]->name;
876
    if( outputParameters )
877
        odevName = hostApi->deviceInfos[outputParameters->device]->name;
878
    PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );
879
    if( inputParameters )
880
    {
881
        PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
882
        PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );
883
    }
884
    if( outputParameters )
885
    {
886
        PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
887
        PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );
888
    }
889

    
890
    if( callback != NULL )
891
    {
892
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
893
                                               &ossApi->callbackStreamInterface, callback, userData );
894
        stream->callbackMode = 1;
895
    }
896
    else
897
    {
898
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
899
                                               &ossApi->blockingStreamInterface, callback, userData );
900
    }
901

    
902
    ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );
903

    
904
error:
905
    return result;
906
}
907

    
908
static void PaOssStream_Terminate( PaOssStream *stream )
909
{
910
    assert( stream );
911

    
912
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
913
    PaUtil_TerminateThreading( &stream->threading );
914

    
915
    if( stream->capture )
916
        PaOssStreamComponent_Terminate( stream->capture );
917
    if( stream->playback )
918
        PaOssStreamComponent_Terminate( stream->playback );
919

    
920
    sem_destroy( &stream->semaphore );
921

    
922
    PaUtil_FreeMemory( stream );
923
}
924

    
925
/** Translate from PA format to OSS native.
926
 *
927
 */
928
static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )
929
{
930
    switch( paFormat )
931
    {
932
        case paUInt8:
933
            *ossFormat = AFMT_U8;
934
            break;
935
        case paInt8:
936
            *ossFormat = AFMT_S8;
937
            break;
938
        case paInt16:
939
            *ossFormat = AFMT_S16_NE;
940
            break;
941
        default:
942
            return paInternalError;     /* This shouldn't happen */
943
    }
944

    
945
    return paNoError;
946
}
947

    
948
/** Return the PA-compatible formats that this device can support.
949
 *
950
 */
951
static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )
952
{
953
    PaError result = paNoError;
954
    int mask = 0;
955
    PaSampleFormat frmts = 0;
956

    
957
    ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );
958
    if( mask & AFMT_U8 )
959
        frmts |= paUInt8;
960
    if( mask & AFMT_S8 )
961
        frmts |= paInt8;
962
    if( mask & AFMT_S16_NE )
963
        frmts |= paInt16;
964
    else
965
        result = paSampleFormatNotSupported;
966

    
967
    *availableFormats = frmts;
968

    
969
error:
970
    return result;
971
}
972

    
973
static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )
974
{
975
    return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;
976
}
977

    
978
/** Buffer size in bytes.
979
 *
980
 */
981
static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )
982
{
983
    return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
984
}
985

    
986
/** Configure stream component device parameters.
987
 */
988
static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long
989
        framesPerBuffer, StreamMode streamMode, PaOssStreamComponent *master )
990
{
991
    PaError result = paNoError;
992
    int temp, nativeFormat;
993
    int sr = (int)sampleRate;
994
    PaSampleFormat availableFormats = 0, hostFormat = 0;
995
    int chans = component->userChannelCount;
996
    int frgmt;
997
    int numBufs;
998
    int bytesPerBuf;
999
    unsigned long bufSz;
1000
    unsigned long fragSz;
1001
    audio_buf_info bufInfo;
1002

    
1003
    /* We may have a situation where only one component (the master) is configured, if both point to the same device.
1004
     * In that case, the second component will copy settings from the other */
1005
    if( !master )
1006
    {
1007
        /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.
1008
         * The hardware need not respect the requested fragment size, so we may have to adapt.
1009
         */
1010
        if( framesPerBuffer == paFramesPerBufferUnspecified )
1011
        {
1012
            /* Aim for 4 fragments in the complete buffer; the latency comes from 3 of these */
1013
            fragSz = (unsigned long)(component->latency * sampleRate / 3);
1014
            bufSz = fragSz * 4;
1015
        }
1016
        else
1017
        {
1018
            fragSz = framesPerBuffer;
1019
            bufSz = (unsigned long)(component->latency * sampleRate) + fragSz; /* Latency + 1 buffer */
1020
        }
1021

    
1022
        PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );
1023
        hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );
1024

    
1025
        /* OSS demands at least 2 buffers, and 16 bytes per buffer */
1026
        numBufs = (int)PA_MAX( bufSz / fragSz, 2 );
1027
        bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );
1028

    
1029
        /* The fragment parameters are encoded like this:
1030
         * Most significant byte: number of fragments
1031
         * Least significant byte: exponent of fragment size (i.e., for 256, 8)
1032
         */
1033
        frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);
1034
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
1035

    
1036
        /* A: according to the OSS programmer's guide parameters should be set in this order:
1037
         * format, channels, rate */
1038

    
1039
        /* This format should be deemed good before we get this far */
1040
        PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );
1041
        nativeFormat = temp;
1042
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );
1043
        PA_UNLESS( temp == nativeFormat, paInternalError );
1044

    
1045
        /* try to set the number of channels */
1046
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported );   /* XXX: Should be paInvalidChannelCount? */
1047
        /* It's possible that the minimum number of host channels is greater than what the user requested */
1048
        PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );
1049

    
1050
        /* try to set the sample rate */
1051
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );
1052

    
1053
        /* reject if there's no sample rate within 1% of the one requested */
1054
        if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )
1055
        {
1056
            PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));
1057
            PA_ENSURE( paInvalidSampleRate );
1058
        }
1059

    
1060
        ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),
1061
                paUnanticipatedHostError );
1062
        component->numBufs = bufInfo.fragstotal;
1063

    
1064
        /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */
1065
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );
1066

    
1067
        component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;
1068
        component->hostChannelCount = chans;
1069
        component->hostFormat = hostFormat;
1070
    }
1071
    else
1072
    {
1073
        component->hostFormat = master->hostFormat;
1074
        component->hostFrames = master->hostFrames;
1075
        component->hostChannelCount = master->hostChannelCount;
1076
        component->numBufs = master->numBufs;
1077
    }
1078

    
1079
    PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),
1080
            paInsufficientMemory );
1081

    
1082
error:
1083
    return result;
1084
}
1085

    
1086
static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )
1087
{
1088
    PaError result = paNoError;
1089
    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
1090
    ssize_t bytesRead;
1091

    
1092
    ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );
1093
    *frames = bytesRead / PaOssStreamComponent_FrameSize( component );
1094
    /* TODO: Handle condition where number of frames read doesn't equal number of frames requested */
1095

    
1096
error:
1097
    return result;
1098
}
1099

    
1100
static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )
1101
{
1102
    PaError result = paNoError;
1103
    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
1104
    ssize_t bytesWritten;
1105

    
1106
    ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );
1107
    *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );
1108
    /* TODO: Handle condition where number of frames written doesn't equal number of frames requested */
1109

    
1110
error:
1111
    return result;
1112
}
1113

    
1114
/** Configure the stream according to input/output parameters.
1115
 *
1116
 * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by
1117
 * the user, if so we'll record the actual number of host channels and adapt later.
1118
 */
1119
static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,
1120
        double *inputLatency, double *outputLatency )
1121
{
1122
    PaError result = paNoError;
1123
    int duplex = stream->capture && stream->playback;
1124
    unsigned long framesPerHostBuffer = 0;
1125

    
1126
    /* We should request full duplex first thing after opening the device */
1127
    if( duplex && stream->sharedDevice )
1128
        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );
1129

    
1130
    if( stream->capture )
1131
    {
1132
        PaOssStreamComponent *component = stream->capture;
1133
        PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In,
1134
                    NULL ) );
1135

    
1136
        assert( component->hostChannelCount > 0 );
1137
        assert( component->hostFrames > 0 );
1138

    
1139
        *inputLatency = (component->hostFrames * (component->numBufs - 1)) / sampleRate;
1140
    }
1141
    if( stream->playback )
1142
    {
1143
        PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL;
1144
        PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out,
1145
                    master ) );
1146

    
1147
        assert( component->hostChannelCount > 0 );
1148
        assert( component->hostFrames > 0 );
1149

    
1150
        *outputLatency = (component->hostFrames * (component->numBufs - 1)) / sampleRate;
1151
    }
1152

    
1153
    if( duplex )
1154
        framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames );
1155
    else if( stream->capture )
1156
        framesPerHostBuffer = stream->capture->hostFrames;
1157
    else if( stream->playback )
1158
        framesPerHostBuffer = stream->playback->hostFrames;
1159

    
1160
    stream->framesPerHostBuffer = framesPerHostBuffer;
1161
    stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate );    /* Period in usecs, rounded up */
1162

    
1163
    stream->sampleRate = stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
1164

    
1165
error:
1166
    return result;
1167
}
1168

    
1169
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
1170

    
1171
/** Open a PA OSS stream.
1172
 *
1173
 * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the
1174
 * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both
1175
 * directions are the same device we will demand the same number of channels. The number of channels can range
1176
 * from 1 to the maximum supported by the device.
1177
 *
1178
 * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback
1179
 * must reflect this, in addition the host latency per device should approximate the corresponding
1180
 * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that
1181
 * both capture and playback can agree on (they can be different devices), the buffer processor can adapt
1182
 * between host and user buffer size, but the ratio should preferably be integral.
1183
 */
1184
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1185
                           PaStream** s,
1186
                           const PaStreamParameters *inputParameters,
1187
                           const PaStreamParameters *outputParameters,
1188
                           double sampleRate,
1189
                           unsigned long framesPerBuffer,
1190
                           PaStreamFlags streamFlags,
1191
                           PaStreamCallback *streamCallback,
1192
                           void *userData )
1193
{
1194
    PaError result = paNoError;
1195
    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
1196
    PaOssStream *stream = NULL;
1197
    int inputChannelCount = 0, outputChannelCount = 0;
1198
    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0;
1199
    const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0;
1200
    int bpInitialized = 0;
1201
    double inLatency = 0., outLatency = 0.;
1202
    int i = 0;
1203

    
1204
    /* validate platform specific flags */
1205
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
1206
        return paInvalidFlag; /* unexpected platform specific flag */
1207

    
1208
    if( inputParameters )
1209
    {
1210
        /* unless alternate device specification is supported, reject the use of
1211
            paUseHostApiSpecificDeviceSpecification */
1212
        inputDeviceInfo = hostApi->deviceInfos[inputParameters->device];
1213
        PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) );
1214

    
1215
        inputChannelCount = inputParameters->channelCount;
1216
        inputSampleFormat = inputParameters->sampleFormat;
1217
    }
1218
    if( outputParameters )
1219
    {
1220
        outputDeviceInfo = hostApi->deviceInfos[outputParameters->device];
1221
        PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) );
1222

    
1223
        outputChannelCount = outputParameters->channelCount;
1224
        outputSampleFormat = outputParameters->sampleFormat;
1225
    }
1226

    
1227
    /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same
1228
     * device is opened for both directions
1229
     */
1230
    if( inputChannelCount > 0 && outputChannelCount > 0 )
1231
    {
1232
        if( inputParameters->device == outputParameters->device )
1233
        {
1234
            if( inputParameters->channelCount != outputParameters->channelCount )
1235
                return paInvalidChannelCount;
1236
        }
1237
    }
1238

    
1239
    /* Round framesPerBuffer to the next power-of-two to make OSS happy. */
1240
    if( framesPerBuffer != paFramesPerBufferUnspecified )
1241
    {
1242
        framesPerBuffer &= INT_MAX;
1243
        for (i = 1; framesPerBuffer > i; i <<= 1) ;
1244
        framesPerBuffer = i;
1245
    }
1246

    
1247
    /* allocate and do basic initialization of the stream structure */
1248
    PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory );
1249
    PA_ENSURE( PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi ) );
1250

    
1251
    PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) );
1252

    
1253
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
1254

    
1255
    if( inputParameters )
1256
    {
1257
        inputHostFormat = stream->capture->hostFormat;
1258
        stream->streamRepresentation.streamInfo.inputLatency = inLatency +
1259
            PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) / sampleRate;
1260
    }
1261
    if( outputParameters )
1262
    {
1263
        outputHostFormat = stream->playback->hostFormat;
1264
        stream->streamRepresentation.streamInfo.outputLatency = outLatency +
1265
            PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate;
1266
    }
1267

    
1268
    /* Initialize buffer processor with fixed host buffer size.
1269
     * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will
1270
     * convert between the two.
1271
     */
1272
    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
1273
              inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat,
1274
              outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer,
1275
              paUtilFixedHostBufferSize, streamCallback, userData ) );
1276
    bpInitialized = 1;
1277

    
1278
    *s = (PaStream*)stream;
1279

    
1280
    return result;
1281

    
1282
error:
1283
    if( bpInitialized )
1284
        PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
1285
    if( stream )
1286
        PaOssStream_Terminate( stream );
1287

    
1288
    return result;
1289
}
1290

    
1291
/*! Poll on I/O filedescriptors.
1292

1293
  Poll till we've determined there's data for read or write. In the full-duplex case,
1294
  we don't want to hang around forever waiting for either input or output frames, so
1295
  whenever we have a timed out filedescriptor we check if we're nearing under/overrun
1296
  for the other direction (critical limit set at one buffer). If so, we exit the waiting
1297
  state, and go on with what we got. We align the number of frames on a host buffer
1298
  boundary because it is possible that the buffer size differs for the two directions and
1299
  the host buffer size is a compromise between the two.
1300
  */
1301
static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames )
1302
{
1303
    PaError result = paNoError;
1304
    int pollPlayback = 0, pollCapture = 0;
1305
    int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;
1306
    audio_buf_info bufInfo;
1307
    /* int ofs = 0, nfds = stream->nfds; */
1308
    fd_set readFds, writeFds;
1309
    int nfds = 0;
1310
    struct timeval selectTimeval = {0, 0};
1311
    unsigned long timeout = stream->pollTimeout;    /* In usecs */
1312
    int captureFd = -1, playbackFd = -1;
1313

    
1314
    assert( stream );
1315
    assert( frames );
1316

    
1317
    if( stream->capture )
1318
    {
1319
        pollCapture = 1;
1320
        captureFd = stream->capture->fd;
1321
        /* stream->capture->pfd->events = POLLIN; */
1322
    }
1323
    if( stream->playback )
1324
    {
1325
        pollPlayback = 1;
1326
        playbackFd = stream->playback->fd;
1327
        /* stream->playback->pfd->events = POLLOUT; */
1328
    }
1329

    
1330
    FD_ZERO( &readFds );
1331
    FD_ZERO( &writeFds );
1332

    
1333
    while( pollPlayback || pollCapture )
1334
    {
1335
#ifdef PTHREAD_CANCELED
1336
        pthread_testcancel();
1337
#else
1338
        /* avoid indefinite waiting on thread not supporting cancelation */
1339
        if( stream->callbackStop || stream->callbackAbort )
1340
        {
1341
            PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" ));
1342
            (*frames) = 0;
1343
            return paNoError;
1344
        }
1345
#endif
1346

    
1347
        /* select may modify the timeout parameter */
1348
        selectTimeval.tv_usec = timeout;
1349
        nfds = 0;
1350

    
1351
        if( pollCapture )
1352
        {
1353
            FD_SET( captureFd, &readFds );
1354
            nfds = captureFd + 1;
1355
        }
1356
        if( pollPlayback )
1357
        {
1358
            FD_SET( playbackFd, &writeFds );
1359
            nfds = PA_MAX( nfds, playbackFd + 1 );
1360
        }
1361
        ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError );
1362
        /*
1363
        if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 )
1364
        {
1365

1366
            ENSURE_( -1, paUnanticipatedHostError );
1367
        }
1368
        */
1369
#ifdef PTHREAD_CANCELED
1370
        pthread_testcancel();
1371
#else
1372
        /* avoid indefinite waiting on thread not supporting cancelation */
1373
        if( stream->callbackStop || stream->callbackAbort )
1374
        {
1375
            PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" ));
1376
            (*frames) = 0;
1377
            return paNoError;
1378
        }
1379
#endif
1380
        if( pollCapture )
1381
        {
1382
            if( FD_ISSET( captureFd, &readFds ) )
1383
            {
1384
                FD_CLR( captureFd, &readFds );
1385
                pollCapture = 0;
1386
            }
1387
            /*
1388
            if( stream->capture->pfd->revents & POLLIN )
1389
            {
1390
                --nfds;
1391
                ++ofs;
1392
                pollCapture = 0;
1393
            }
1394
            */
1395
            else if( stream->playback ) /* Timed out, go on with playback? */
1396
            {
1397
                /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n",
1398
                            __FUNCTION__, stream->pollTimeout ));*/
1399
            }
1400
        }
1401
        if( pollPlayback )
1402
        {
1403
            if( FD_ISSET( playbackFd, &writeFds ) )
1404
            {
1405
                FD_CLR( playbackFd, &writeFds );
1406
                pollPlayback = 0;
1407
            }
1408
            /*
1409
            if( stream->playback->pfd->revents & POLLOUT )
1410
            {
1411
                --nfds;
1412
                pollPlayback = 0;
1413
            }
1414
            */
1415
            else if( stream->capture )  /* Timed out, go on with capture? */
1416
            {
1417
                /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n",
1418
                            __FUNCTION__, stream->pollTimeout ));*/
1419
            }
1420
        }
1421
    }
1422

    
1423
    if( stream->capture )
1424
    {
1425
        ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError );
1426
        captureAvail = bufInfo.fragments * stream->capture->hostFrames;
1427
        if( !captureAvail )
1428
            PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ ));
1429

    
1430
        captureAvail = captureAvail == 0 ? INT_MAX : captureAvail;      /* Disregard if zero */
1431
    }
1432
    if( stream->playback )
1433
    {
1434
        ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError );
1435
        playbackAvail = bufInfo.fragments * stream->playback->hostFrames;
1436
        if( !playbackAvail )
1437
        {
1438
            PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ ));
1439
        }
1440

    
1441
        playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail;      /* Disregard if zero */
1442
    }
1443

    
1444
    commonAvail = PA_MIN( captureAvail, playbackAvail );
1445
    if( commonAvail == INT_MAX )
1446
        commonAvail = 0;
1447
    commonAvail -= commonAvail % stream->framesPerHostBuffer;
1448

    
1449
    assert( commonAvail != INT_MAX );
1450
    assert( commonAvail >= 0 );
1451
    *frames = commonAvail;
1452

    
1453
error:
1454
    return result;
1455
}
1456

    
1457
/** Prepare stream for capture/playback.
1458
 *
1459
 * In order to synchronize capture and playback properly we use the SETTRIGGER command.
1460
 */
1461
static PaError PaOssStream_Prepare( PaOssStream *stream )
1462
{
1463
    PaError result = paNoError;
1464
    int enableBits = 0;
1465

    
1466
    if( stream->triggered )
1467
        return result;
1468

    
1469
    /* The OSS reference instructs us to clear direction bits before setting them.*/
1470
    if( stream->playback )
1471
        ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
1472
    if( stream->capture )
1473
        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
1474

    
1475
    if( stream->playback )
1476
    {
1477
        size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback );
1478
        memset( stream->playback->buffer, 0, bufSz );
1479

    
1480
        /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer
1481
         * OSS will complain. */
1482
        PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
1483
        while (1)
1484
        {
1485
            if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 )
1486
                break;
1487
        }
1488
        PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) );
1489
    }
1490

    
1491
    if( stream->sharedDevice )
1492
    {
1493
        enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
1494
        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
1495
    }
1496
    else
1497
    {
1498
        if( stream->capture )
1499
        {
1500
            enableBits = PCM_ENABLE_INPUT;
1501
            ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
1502
        }
1503
        if( stream->playback )
1504
        {
1505
            enableBits = PCM_ENABLE_OUTPUT;
1506
            ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
1507
        }
1508
    }
1509

    
1510
    /* Ok, we have triggered the stream */
1511
    stream->triggered = 1;
1512

    
1513
error:
1514
    return result;
1515
}
1516

    
1517
/** Stop audio processing
1518
 *
1519
 */
1520
static PaError PaOssStream_Stop( PaOssStream *stream, int abort )
1521
{
1522
    PaError result = paNoError;
1523

    
1524
    /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST.
1525
     * Also disable capture/playback till the stream is started again.
1526
     */
1527
    int captureErr = 0, playbackErr = 0;
1528
    if( stream->capture )
1529
    {
1530
        if( (captureErr = ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 )) < 0 )
1531
        {
1532
            PA_DEBUG(( "%s: Failed to stop capture device, error: %d\n", __FUNCTION__, captureErr ));
1533
        }
1534
    }
1535
    if( stream->playback && !stream->sharedDevice )
1536
    {
1537
        if( (playbackErr = ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 )) < 0 )
1538
        {
1539
            PA_DEBUG(( "%s: Failed to stop playback device, error: %d\n", __FUNCTION__, playbackErr ));
1540
        }
1541
    }
1542

    
1543
    if( captureErr || playbackErr )
1544
    {
1545
        result = paUnanticipatedHostError;
1546
    }
1547

    
1548
    return result;
1549
}
1550

    
1551
/** Clean up after thread exit.
1552
 *
1553
 * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here
1554
 */
1555
static void OnExit( void *data )
1556
{
1557
    PaOssStream *stream = (PaOssStream *) data;
1558
    assert( data );
1559

    
1560
    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
1561

    
1562
    PaOssStream_Stop( stream, stream->callbackAbort );
1563

    
1564
    PA_DEBUG(( "OnExit: Stoppage\n" ));
1565

    
1566
    /* Eventually notify user all buffers have played */
1567
    if( stream->streamRepresentation.streamFinishedCallback )
1568
        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
1569

    
1570
    stream->callbackAbort = 0;      /* Clear state */
1571
    stream->isActive = 0;
1572
}
1573

    
1574
static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail )
1575
{
1576
    PaError result = paNoError;
1577

    
1578
    if( stream->capture )
1579
    {
1580
        PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer,
1581
                stream->capture->hostChannelCount );
1582
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail );
1583
    }
1584
    if( stream->playback )
1585
    {
1586
        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer,
1587
                stream->playback->hostChannelCount );
1588
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail );
1589
    }
1590

    
1591
    return result;
1592
}
1593

    
1594
/** Thread procedure for callback processing.
1595
 *
1596
 * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the
1597
 * callback should be used for buffer priming. When the stream is cancelled a separate function will
1598
 * take care of the transition to the Callback Finished state (the stream isn't considered Stopped
1599
 * before StopStream() or AbortStream() are called).
1600
 */
1601
static void *PaOSS_AudioThreadProc( void *userData )
1602
{
1603
    PaError result = paNoError;
1604
    PaOssStream *stream = (PaOssStream*)userData;
1605
    unsigned long framesAvail = 0, framesProcessed = 0;
1606
    int callbackResult = paContinue;
1607
    int triggered = stream->triggered;  /* See if SNDCTL_DSP_TRIGGER has been issued already */
1608
    int initiateProcessing = triggered;    /* Already triggered? */
1609
    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
1610
    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
1611

    
1612
    /*
1613
#if ( SOUND_VERSION > 0x030904 )
1614
        audio_errinfo errinfo;
1615
#endif
1616
*/
1617

    
1618
    assert( stream );
1619

    
1620
    pthread_cleanup_push( &OnExit, stream );        /* Execute OnExit when exiting */
1621

    
1622
    /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and
1623
     * playback in sync, when the stream is restarted after being stopped we simply start by reading/
1624
     * writing.
1625
     */
1626
    PA_ENSURE( PaOssStream_Prepare( stream ) );
1627

    
1628
    /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */
1629
    if( initiateProcessing )
1630
    {
1631
        /* Make sure devices are in blocking mode */
1632
        if( stream->capture )
1633
            ModifyBlocking( stream->capture->fd, 1 );
1634
        if( stream->playback )
1635
            ModifyBlocking( stream->playback->fd, 1 );
1636
    }
1637

    
1638
    while( 1 )
1639
    {
1640
#ifdef PTHREAD_CANCELED
1641
        pthread_testcancel();
1642
#else
1643
        if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */
1644
        {
1645
            PA_DEBUG(( "Aborting callback thread\n" ));
1646
            break;
1647
        }
1648
#endif
1649
        if( stream->callbackStop && callbackResult == paContinue )
1650
        {
1651
            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
1652
            callbackResult = paComplete;
1653
        }
1654

    
1655
        /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless
1656
         * the stream has been recently started, we will have to go right ahead and read/write in blocking
1657
         * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch
1658
         * to non-blocking mode.
1659
         */
1660
        if( !initiateProcessing )
1661
        {
1662
            /* Wait on available frames */
1663
            PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) );
1664
            assert( framesAvail % stream->framesPerHostBuffer == 0 );
1665
        }
1666
        else
1667
        {
1668
            framesAvail = stream->framesPerHostBuffer;
1669
        }
1670

    
1671
        while( framesAvail > 0 )
1672
        {
1673
            unsigned long frames = framesAvail;
1674

    
1675
#ifdef PTHREAD_CANCELED
1676
            pthread_testcancel();
1677
#else
1678
            if( stream->callbackStop )
1679
            {
1680
                PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
1681
                callbackResult = paComplete;
1682
            }
1683

    
1684
            if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */
1685
            {
1686
                PA_DEBUG(( "Aborting callback thread\n" ));
1687
                break;
1688
            }
1689
#endif
1690
            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
1691

    
1692
            /* Read data */
1693
            if ( stream->capture )
1694
            {
1695
                PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) );
1696
                if( frames < framesAvail )
1697
                {
1698
                    PA_DEBUG(( "Read %lu less frames than requested\n", framesAvail - frames ));
1699
                    framesAvail = frames;
1700
                }
1701
            }
1702

    
1703
#if ( SOUND_VERSION >= 0x030904 )
1704
            /*
1705
               Check with OSS to see if there have been any under/overruns
1706
               since last time we checked.
1707
               */
1708
            /*
1709
            if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 )
1710
            {
1711
                if( errinfo.play_underruns )
1712
                    cbFlags |= paOutputUnderflow ;
1713
                if( errinfo.record_underruns )
1714
                    cbFlags |= paInputUnderflow ;
1715
            }
1716
            else
1717
                PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) ));
1718
                */
1719
#endif
1720

    
1721
            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
1722
                    cbFlags );
1723
            cbFlags = 0;
1724
            PA_ENSURE( SetUpBuffers( stream, framesAvail ) );
1725

    
1726
            framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
1727
                    &callbackResult );
1728
            assert( framesProcessed == framesAvail );
1729
            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
1730

    
1731
            if ( stream->playback )
1732
            {
1733
                frames = framesAvail;
1734

    
1735
                PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) );
1736
                if( frames < framesAvail )
1737
                {
1738
                    /* TODO: handle bytesWritten != bytesRequested (slippage?) */
1739
                    PA_DEBUG(( "Wrote %lu less frames than requested\n", framesAvail - frames ));
1740
                }
1741
            }
1742

    
1743
            framesAvail -= framesProcessed;
1744
            stream->framesProcessed += framesProcessed;
1745

    
1746
            if( callbackResult != paContinue )
1747
                break;
1748
        }
1749

    
1750
        if( initiateProcessing || !triggered )
1751
        {
1752
            /* Non-blocking */
1753
            if( stream->capture )
1754
                PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) );
1755
            if( stream->playback && !stream->sharedDevice )
1756
                PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
1757

    
1758
            initiateProcessing = 0;
1759
            sem_post( &stream->semaphore );
1760
        }
1761

    
1762
        if( callbackResult != paContinue )
1763
        {
1764
            stream->callbackAbort = callbackResult == paAbort;
1765
            if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
1766
                break;
1767
        }
1768
    }
1769

    
1770
    pthread_cleanup_pop( 1 );
1771

    
1772
error:
1773
    pthread_exit( NULL );
1774
}
1775

    
1776
/** Close the stream.
1777
 *
1778
 */
1779
static PaError CloseStream( PaStream* s )
1780
{
1781
    PaError result = paNoError;
1782
    PaOssStream *stream = (PaOssStream*)s;
1783

    
1784
    assert( stream );
1785

    
1786
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
1787
    PaOssStream_Terminate( stream );
1788

    
1789
    return result;
1790
}
1791

    
1792
/** Start the stream.
1793
 *
1794
 * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual
1795
 * callback will be repeatedly called in a separate thread. If a separate thread is started this function
1796
 * will block untill it has started processing audio, otherwise audio processing is started directly.
1797
 */
1798
static PaError StartStream( PaStream *s )
1799
{
1800
    PaError result = paNoError;
1801
    PaOssStream *stream = (PaOssStream*)s;
1802

    
1803
    stream->isActive = 1;
1804
    stream->isStopped = 0;
1805
    stream->lastPosPtr = 0;
1806
    stream->lastStreamBytes = 0;
1807
    stream->framesProcessed = 0;
1808

    
1809
    /* only use the thread for callback streams */
1810
    if( stream->bufferProcessor.streamCallback )
1811
    {
1812
        PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) );
1813
        sem_wait( &stream->semaphore );
1814
    }
1815
    else
1816
        PA_ENSURE( PaOssStream_Prepare( stream ) );
1817

    
1818
error:
1819
    return result;
1820
}
1821

    
1822
static PaError RealStop( PaOssStream *stream, int abort )
1823
{
1824
    PaError result = paNoError;
1825

    
1826
    if( stream->callbackMode )
1827
    {
1828
        if( abort )
1829
            stream->callbackAbort = 1;
1830
        else
1831
            stream->callbackStop = 1;
1832

    
1833
        PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) );
1834

    
1835
        stream->callbackStop = stream->callbackAbort = 0;
1836
    }
1837
    else
1838
        PA_ENSURE( PaOssStream_Stop( stream, abort ) );
1839

    
1840
    stream->isStopped = 1;
1841

    
1842
error:
1843
    return result;
1844
}
1845

    
1846
/** Stop the stream.
1847
 *
1848
 * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued
1849
 * buffers.
1850
 */
1851
static PaError StopStream( PaStream *s )
1852
{
1853
    return RealStop( (PaOssStream *)s, 0 );
1854
}
1855

    
1856
/** Abort the stream.
1857
 *
1858
 * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued
1859
 * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing
1860
 * the OSS device.
1861
 */
1862
static PaError AbortStream( PaStream *s )
1863
{
1864
    return RealStop( (PaOssStream *)s, 1 );
1865
}
1866

    
1867
/** Is the stream in the Stopped state.
1868
 *
1869
 */
1870
static PaError IsStreamStopped( PaStream *s )
1871
{
1872
    PaOssStream *stream = (PaOssStream*)s;
1873

    
1874
    return (stream->isStopped);
1875
}
1876

    
1877
/** Is the stream in the Active state.
1878
 *
1879
 */
1880
static PaError IsStreamActive( PaStream *s )
1881
{
1882
    PaOssStream *stream = (PaOssStream*)s;
1883

    
1884
    return (stream->isActive);
1885
}
1886

    
1887
static PaTime GetStreamTime( PaStream *s )
1888
{
1889
    PaOssStream *stream = (PaOssStream*)s;
1890
    count_info info;
1891
    int delta;
1892

    
1893
    if( stream->playback ) {
1894
        if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) {
1895
            delta = ( info.bytes - stream->lastPosPtr ) /* & 0x000FFFFF*/;
1896
            return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate;
1897
        }
1898
    }
1899
    else {
1900
        if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) {
1901
            delta = (info.bytes - stream->lastPosPtr) /*& 0x000FFFFF*/;
1902
            return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate;
1903
        }
1904
    }
1905

    
1906
    /* the ioctl failed, but we can still give a coarse estimate */
1907

    
1908
    return stream->framesProcessed / stream->sampleRate;
1909
}
1910

    
1911

    
1912
static double GetStreamCpuLoad( PaStream* s )
1913
{
1914
    PaOssStream *stream = (PaOssStream*)s;
1915

    
1916
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
1917
}
1918

    
1919

    
1920
/*
1921
    As separate stream interfaces are used for blocking and callback
1922
    streams, the following functions can be guaranteed to only be called
1923
    for blocking streams.
1924
*/
1925

    
1926

    
1927
static PaError ReadStream( PaStream* s,
1928
                           void *buffer,
1929
                           unsigned long frames )
1930
{
1931
    PaError result = paNoError;
1932
    PaOssStream *stream = (PaOssStream*)s;
1933
    int bytesRequested, bytesRead;
1934
    unsigned long framesRequested;
1935
    void *userBuffer;
1936

    
1937
    /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers,
1938
     * so we copy the user provided pointers */
1939
    if( stream->bufferProcessor.userInputIsInterleaved )
1940
        userBuffer = buffer;
1941
    else /* Copy channels into local array */
1942
    {
1943
        userBuffer = stream->capture->userBuffers;
1944
        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount );
1945
    }
1946

    
1947
    while( frames )
1948
    {
1949
        framesRequested = PA_MIN( frames, stream->capture->hostFrames );
1950

    
1951
        bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture );
1952
        ENSURE_( (bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested )),
1953
                 paUnanticipatedHostError );
1954
        if ( bytesRequested != bytesRead )
1955
        {
1956
            PA_DEBUG(( "Requested %d bytes, read %d\n", bytesRequested, bytesRead ));
1957
            return paUnanticipatedHostError;
1958
        }
1959

    
1960
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames );
1961
        PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount );
1962
        PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested );
1963
        frames -= framesRequested;
1964
    }
1965

    
1966
error:
1967
    return result;
1968
}
1969

    
1970

    
1971
static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames )
1972
{
1973
    PaError result = paNoError;
1974
    PaOssStream *stream = (PaOssStream*)s;
1975
    int bytesRequested, bytesWritten;
1976
    unsigned long framesConverted;
1977
    const void *userBuffer;
1978

    
1979
    /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers,
1980
     * so we copy the user provided pointers */
1981
    if( stream->bufferProcessor.userOutputIsInterleaved )
1982
        userBuffer = buffer;
1983
    else
1984
    {
1985
        /* Copy channels into local array */
1986
        userBuffer = stream->playback->userBuffers;
1987
        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount );
1988
    }
1989

    
1990
    while( frames )
1991
    {
1992
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames );
1993
        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount );
1994

    
1995
        framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames );
1996
        frames -= framesConverted;
1997

    
1998
        bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback );
1999
        ENSURE_( (bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested )),
2000
                 paUnanticipatedHostError );
2001

    
2002
        if ( bytesRequested != bytesWritten )
2003
        {
2004
            PA_DEBUG(( "Requested %d bytes, wrote %d\n", bytesRequested, bytesWritten ));
2005
            return paUnanticipatedHostError;
2006
        }
2007
    }
2008

    
2009
error:
2010
    return result;
2011
}
2012

    
2013

    
2014
static signed long GetStreamReadAvailable( PaStream* s )
2015
{
2016
    PaError result = paNoError;
2017
    PaOssStream *stream = (PaOssStream*)s;
2018
    audio_buf_info info;
2019

    
2020
    ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ), paUnanticipatedHostError );
2021
    return info.fragments * stream->capture->hostFrames;
2022

    
2023
error:
2024
    return result;
2025
}
2026

    
2027

    
2028
/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */
2029
static signed long GetStreamWriteAvailable( PaStream* s )
2030
{
2031
    PaError result = paNoError;
2032
    PaOssStream *stream = (PaOssStream*)s;
2033
    int delay = 0;
2034
#ifdef SNDCTL_DSP_GETODELAY
2035
    ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ), paUnanticipatedHostError );
2036
#endif
2037
    return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback );
2038

    
2039
/* Conditionally compile this to avoid warning about unused label */
2040
#ifdef SNDCTL_DSP_GETODELAY
2041
error:
2042
    return result;
2043
#endif
2044
}
2045