~ubuntu-branches/ubuntu/vivid/sflphone/vivid

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/portaudio/pablio/pablio.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-30 11:40:56 UTC
  • mfrom: (4.1.18 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130630114056-0np50jkyqo6vnmii
Tags: 1.2.3-2
* changeset_r92d62cfc54732bbbcfff2b1d36c096b120b981a5.diff 
  - fixes automatic endian detection 
* Update Vcs: fixes vcs-field-not-canonical

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: pablio.c 1151 2006-11-29 02:11:16Z leland_lucius $
 
3
 * pablio.c
 
4
 * Portable Audio Blocking Input/Output utility.
 
5
 *
 
6
 * Author: Phil Burk, http://www.softsynth.com
 
7
 *
 
8
 * This program uses the PortAudio Portable Audio Library.
 
9
 * For more information see: http://www.portaudio.com
 
10
 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
 
11
 *
 
12
 * Permission is hereby granted, free of charge, to any person obtaining
 
13
 * a copy of this software and associated documentation files
 
14
 * (the "Software"), to deal in the Software without restriction,
 
15
 * including without limitation the rights to use, copy, modify, merge,
 
16
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
17
 * and to permit persons to whom the Software is furnished to do so,
 
18
 * subject to the following conditions:
 
19
 *
 
20
 * The above copyright notice and this permission notice shall be
 
21
 * included in all copies or substantial portions of the Software.
 
22
 *
 
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
24
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
25
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
26
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 
27
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 
28
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
29
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
30
 */
 
31
 
 
32
/*
 
33
 * The text above constitutes the entire PortAudio license; however,
 
34
 * the PortAudio community also makes the following non-binding requests:
 
35
 *
 
36
 * Any person wishing to distribute modifications to the Software is
 
37
 * requested to send the modifications to the original developer so that
 
38
 * they can be incorporated into the canonical version. It is also
 
39
 * requested that these non-binding requests be included along with the
 
40
 * license above.
 
41
 */
 
42
 
 
43
#include <stdio.h>
 
44
#include <stdlib.h>
 
45
#include <math.h>
 
46
#include "portaudio.h"
 
47
#include "pa_ringbuffer.h"
 
48
#include "pablio.h"
 
49
#include <string.h>
 
50
 
 
51
/************************************************************************/
 
52
/******** Constants *****************************************************/
 
53
/************************************************************************/
 
54
 
 
55
#define FRAMES_PER_BUFFER    (256)
 
56
 
 
57
/************************************************************************/
 
58
/******** Prototypes ****************************************************/
 
59
/************************************************************************/
 
60
 
 
61
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
 
62
                               unsigned long framesPerBuffer,
 
63
                               PaTimestamp outTime, void *userData );
 
64
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
 
65
static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
 
66
 
 
67
/************************************************************************/
 
68
/******** Functions *****************************************************/
 
69
/************************************************************************/
 
70
 
 
71
/* Called from PortAudio.
 
72
 * Read and write data only if there is room in FIFOs.
 
73
 */
 
74
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
 
75
                               unsigned long framesPerBuffer,
 
76
                               PaTimestamp outTime, void *userData )
 
77
{
 
78
    PABLIO_Stream *data = (PABLIO_Stream*)userData;
 
79
    long numBytes = data->bytesPerFrame * framesPerBuffer;
 
80
    (void) outTime;
 
81
 
 
82
    /* This may get called with NULL inputBuffer during initial setup. */
 
83
    if( inputBuffer != NULL )
 
84
    {
 
85
        PaUtil_WriteRingBuffer( &data->inFIFO, inputBuffer, numBytes );
 
86
    }
 
87
    if( outputBuffer != NULL )
 
88
    {
 
89
        int i;
 
90
        int numRead = PaUtil_ReadRingBuffer( &data->outFIFO, outputBuffer, numBytes );
 
91
        /* Zero out remainder of buffer if we run out of data. */
 
92
        for( i=numRead; i<numBytes; i++ )
 
93
        {
 
94
            ((char *)outputBuffer)[i] = 0;
 
95
        }
 
96
    }
 
97
 
 
98
    return 0;
 
99
}
 
100
 
 
101
/* Allocate buffer. */
 
102
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
 
103
{
 
104
    long numBytes = numFrames * bytesPerFrame;
 
105
    char *buffer = (char *) malloc( numBytes );
 
106
    if( buffer == NULL ) return paInsufficientMemory;
 
107
    memset( buffer, 0, numBytes );
 
108
    return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer );
 
109
}
 
110
 
 
111
/* Free buffer. */
 
112
static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
 
113
{
 
114
    if( rbuf->buffer ) free( rbuf->buffer );
 
115
    rbuf->buffer = NULL;
 
116
    return paNoError;
 
117
}
 
118
 
 
119
/************************************************************
 
120
 * Write data to ring buffer.
 
121
 * Will not return until all the data has been written.
 
122
 */
 
123
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
 
124
{
 
125
    long bytesWritten;
 
126
    char *p = (char *) data;
 
127
    long numBytes = aStream->bytesPerFrame * numFrames;
 
128
    while( numBytes > 0)
 
129
    {
 
130
        bytesWritten = PaUtil_WriteRingBuffer( &aStream->outFIFO, p, numBytes );
 
131
        numBytes -= bytesWritten;
 
132
        p += bytesWritten;
 
133
        if( numBytes > 0) Pa_Sleep(10);
 
134
    }
 
135
    return numFrames;
 
136
}
 
137
 
 
138
/************************************************************
 
139
 * Read data from ring buffer.
 
140
 * Will not return until all the data has been read.
 
141
 */
 
142
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
 
143
{
 
144
    long bytesRead;
 
145
    char *p = (char *) data;
 
146
    long numBytes = aStream->bytesPerFrame * numFrames;
 
147
    while( numBytes > 0)
 
148
    {
 
149
        bytesRead = PaUtil_ReadRingBuffer( &aStream->inFIFO, p, numBytes );
 
150
        numBytes -= bytesRead;
 
151
        p += bytesRead;
 
152
        if( numBytes > 0) Pa_Sleep(10);
 
153
    }
 
154
    return numFrames;
 
155
}
 
156
 
 
157
/************************************************************
 
158
 * Return the number of frames that could be written to the stream without
 
159
 * having to wait.
 
160
 */
 
161
long GetAudioStreamWriteable( PABLIO_Stream *aStream )
 
162
{
 
163
    int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
 
164
    return bytesEmpty / aStream->bytesPerFrame;
 
165
}
 
166
 
 
167
/************************************************************
 
168
 * Return the number of frames that are available to be read from the
 
169
 * stream without having to wait.
 
170
 */
 
171
long GetAudioStreamReadable( PABLIO_Stream *aStream )
 
172
{
 
173
    int bytesFull = PaUtil_GetRingBufferReadAvailable( &aStream->inFIFO );
 
174
    return bytesFull / aStream->bytesPerFrame;
 
175
}
 
176
 
 
177
/************************************************************/
 
178
static unsigned long RoundUpToNextPowerOf2( unsigned long n )
 
179
{
 
180
    long numBits = 0;
 
181
    if( ((n-1) & n) == 0) return n; /* Already Power of two. */
 
182
    while( n > 0 )
 
183
    {
 
184
        n= n>>1;
 
185
        numBits++;
 
186
    }
 
187
    return (1<<numBits);
 
188
}
 
189
 
 
190
/************************************************************
 
191
 * Opens a PortAudio stream with default characteristics.
 
192
 * Allocates PABLIO_Stream structure.
 
193
 *
 
194
 * flags parameter can be an ORed combination of:
 
195
 *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
 
196
 *    and either PABLIO_MONO or PABLIO_STEREO
 
197
 */
 
198
PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
 
199
                         PaSampleFormat format, long flags )
 
200
{
 
201
    long   bytesPerSample;
 
202
    long   doRead = 0;
 
203
    long   doWrite = 0;
 
204
    PaError err;
 
205
    PABLIO_Stream *aStream;
 
206
    long   minNumBuffers;
 
207
    long   numFrames;
 
208
 
 
209
    /* Allocate PABLIO_Stream structure for caller. */
 
210
    aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
 
211
    if( aStream == NULL ) return paInsufficientMemory;
 
212
    memset( aStream, 0, sizeof(PABLIO_Stream) );
 
213
 
 
214
    /* Determine size of a sample. */
 
215
    bytesPerSample = Pa_GetSampleSize( format );
 
216
    if( bytesPerSample < 0 )
 
217
    {
 
218
        err = (PaError) bytesPerSample;
 
219
        goto error;
 
220
    }
 
221
    aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;
 
222
    aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
 
223
 
 
224
    /* Initialize PortAudio  */
 
225
    err = Pa_Initialize();
 
226
    if( err != paNoError ) goto error;
 
227
 
 
228
    /* Warning: numFrames must be larger than amount of data processed per interrupt
 
229
     *    inside PA to prevent glitches. Just to be safe, adjust size upwards.
 
230
     */
 
231
    minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
 
232
    numFrames = minNumBuffers * FRAMES_PER_BUFFER;
 
233
    numFrames = RoundUpToNextPowerOf2( numFrames );
 
234
 
 
235
    /* Initialize Ring Buffers */
 
236
    doRead = ((flags & PABLIO_READ) != 0);
 
237
    doWrite = ((flags & PABLIO_WRITE) != 0);
 
238
    if(doRead)
 
239
    {
 
240
        err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );
 
241
        if( err != paNoError ) goto error;
 
242
    }
 
243
    if(doWrite)
 
244
    {
 
245
        long numBytes;
 
246
        err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );
 
247
        if( err != paNoError ) goto error;
 
248
        /* Make Write FIFO appear full initially. */
 
249
        numBytes = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
 
250
        PaUtil_AdvanceRingBufferWriteIndex( &aStream->outFIFO, numBytes );
 
251
    }
 
252
 
 
253
    /* Open a PortAudio stream that we will use to communicate with the underlying
 
254
     * audio drivers. */
 
255
    err = Pa_OpenStream(
 
256
              &aStream->stream,
 
257
              (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice),
 
258
              (doRead ? aStream->samplesPerFrame : 0 ),
 
259
              format,
 
260
              NULL,
 
261
              (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
 
262
              (doWrite ? aStream->samplesPerFrame : 0 ),
 
263
              format,
 
264
              NULL,
 
265
              sampleRate,
 
266
              FRAMES_PER_BUFFER,
 
267
              minNumBuffers,
 
268
              paClipOff,       /* we won't output out of range samples so don't bother clipping them */
 
269
              blockingIOCallback,
 
270
              aStream );
 
271
    if( err != paNoError ) goto error;
 
272
 
 
273
    err = Pa_StartStream( aStream->stream );
 
274
    if( err != paNoError ) goto error;
 
275
 
 
276
    *rwblPtr = aStream;
 
277
    return paNoError;
 
278
 
 
279
error:
 
280
    CloseAudioStream( aStream );
 
281
    *rwblPtr = NULL;
 
282
    return err;
 
283
}
 
284
 
 
285
/************************************************************/
 
286
PaError CloseAudioStream( PABLIO_Stream *aStream )
 
287
{
 
288
    PaError err;
 
289
    int bytesEmpty;
 
290
    int byteSize = aStream->outFIFO.bufferSize;
 
291
 
 
292
    /* If we are writing data, make sure we play everything written. */
 
293
    if( byteSize > 0 )
 
294
    {
 
295
        bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
 
296
        while( bytesEmpty < byteSize )
 
297
        {
 
298
            Pa_Sleep( 10 );
 
299
            bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
 
300
        }
 
301
    }
 
302
 
 
303
    err = Pa_StopStream( aStream->stream );
 
304
    if( err != paNoError ) goto error;
 
305
    err = Pa_CloseStream( aStream->stream );
 
306
    if( err != paNoError ) goto error;
 
307
    Pa_Terminate();
 
308
 
 
309
error:
 
310
    PABLIO_TermFIFO( &aStream->inFIFO );
 
311
    PABLIO_TermFIFO( &aStream->outFIFO );
 
312
    free( aStream );
 
313
    return err;
 
314
}