~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/portaudio/src/common/pa_ringbuffer.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: pa_ringbuffer.c 1421 2009-11-18 16:09:05Z bjornroche $
 
3
 * Portable Audio I/O Library
 
4
 * Ring Buffer utility.
 
5
 *
 
6
 * Author: Phil Burk, http://www.softsynth.com
 
7
 * modified for SMP safety on Mac OS X by Bjorn Roche
 
8
 * modified for SMP safety on Linux by Leland Lucius
 
9
 * also, allowed for const where possible
 
10
 * modified for multiple-byte-sized data elements by Sven Fischer
 
11
 *
 
12
 * Note that this is safe only for a single-thread reader and a
 
13
 * single-thread writer.
 
14
 *
 
15
 * This program uses the PortAudio Portable Audio Library.
 
16
 * For more information see: http://www.portaudio.com
 
17
 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
 
18
 *
 
19
 * Permission is hereby granted, free of charge, to any person obtaining
 
20
 * a copy of this software and associated documentation files
 
21
 * (the "Software"), to deal in the Software without restriction,
 
22
 * including without limitation the rights to use, copy, modify, merge,
 
23
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
24
 * and to permit persons to whom the Software is furnished to do so,
 
25
 * subject to the following conditions:
 
26
 *
 
27
 * The above copyright notice and this permission notice shall be
 
28
 * included in all copies or substantial portions of the Software.
 
29
 *
 
30
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
31
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
32
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
33
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 
34
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 
35
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
36
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
37
 */
 
38
 
 
39
/*
 
40
 * The text above constitutes the entire PortAudio license; however,
 
41
 * the PortAudio community also makes the following non-binding requests:
 
42
 *
 
43
 * Any person wishing to distribute modifications to the Software is
 
44
 * requested to send the modifications to the original developer so that
 
45
 * they can be incorporated into the canonical version. It is also
 
46
 * requested that these non-binding requests be included along with the
 
47
 * license above.
 
48
 */
 
49
 
 
50
/**
 
51
 @file
 
52
 @ingroup common_src
 
53
*/
 
54
 
 
55
#include <stdio.h>
 
56
#include <stdlib.h>
 
57
#include <math.h>
 
58
#include "pa_ringbuffer.h"
 
59
#include <string.h>
 
60
#include "pa_memorybarrier.h"
 
61
 
 
62
/***************************************************************************
 
63
 * Initialize FIFO.
 
64
 * elementCount must be power of 2, returns -1 if not.
 
65
 */
 
66
ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr )
 
67
{
 
68
    if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */
 
69
    rbuf->bufferSize = elementCount;
 
70
    rbuf->buffer = (char *)dataPtr;
 
71
    PaUtil_FlushRingBuffer( rbuf );
 
72
    rbuf->bigMask = (elementCount*2)-1;
 
73
    rbuf->smallMask = (elementCount)-1;
 
74
    rbuf->elementSizeBytes = elementSizeBytes;
 
75
    return 0;
 
76
}
 
77
 
 
78
/***************************************************************************
 
79
** Return number of elements available for reading. */
 
80
ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf )
 
81
{
 
82
    PaUtil_ReadMemoryBarrier();
 
83
    return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
 
84
}
 
85
/***************************************************************************
 
86
** Return number of elements available for writing. */
 
87
ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf )
 
88
{
 
89
    /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */
 
90
    return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf));
 
91
}
 
92
 
 
93
/***************************************************************************
 
94
** Clear buffer. Should only be called when buffer is NOT being read. */
 
95
void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf )
 
96
{
 
97
    rbuf->writeIndex = rbuf->readIndex = 0;
 
98
}
 
99
 
 
100
/***************************************************************************
 
101
** Get address of region(s) to which we can write data.
 
102
** If the region is contiguous, size2 will be zero.
 
103
** If non-contiguous, size2 will be the size of second region.
 
104
** Returns room available to be written or elementCount, whichever is smaller.
 
105
*/
 
106
ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
 
107
                                       void **dataPtr1, ring_buffer_size_t *sizePtr1,
 
108
                                       void **dataPtr2, ring_buffer_size_t *sizePtr2 )
 
109
{
 
110
    ring_buffer_size_t   index;
 
111
    ring_buffer_size_t   available = PaUtil_GetRingBufferWriteAvailable( rbuf );
 
112
    if( elementCount > available ) elementCount = available;
 
113
    /* Check to see if write is not contiguous. */
 
114
    index = rbuf->writeIndex & rbuf->smallMask;
 
115
    if( (index + elementCount) > rbuf->bufferSize )
 
116
    {
 
117
        /* Write data in two blocks that wrap the buffer. */
 
118
        ring_buffer_size_t   firstHalf = rbuf->bufferSize - index;
 
119
        *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
 
120
        *sizePtr1 = firstHalf;
 
121
        *dataPtr2 = &rbuf->buffer[0];
 
122
        *sizePtr2 = elementCount - firstHalf;
 
123
    }
 
124
    else
 
125
    {
 
126
        *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
 
127
        *sizePtr1 = elementCount;
 
128
        *dataPtr2 = NULL;
 
129
        *sizePtr2 = 0;
 
130
    }
 
131
    return elementCount;
 
132
}
 
133
 
 
134
 
 
135
/***************************************************************************
 
136
*/
 
137
ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
 
138
{
 
139
    /* we need to ensure that previous writes are seen before we update the write index */
 
140
    PaUtil_WriteMemoryBarrier();
 
141
    return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask;
 
142
}
 
143
 
 
144
/***************************************************************************
 
145
** Get address of region(s) from which we can read data.
 
146
** If the region is contiguous, size2 will be zero.
 
147
** If non-contiguous, size2 will be the size of second region.
 
148
** Returns room available to be written or elementCount, whichever is smaller.
 
149
*/
 
150
ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
 
151
                                void **dataPtr1, ring_buffer_size_t *sizePtr1,
 
152
                                void **dataPtr2, ring_buffer_size_t *sizePtr2 )
 
153
{
 
154
    ring_buffer_size_t   index;
 
155
    ring_buffer_size_t   available = PaUtil_GetRingBufferReadAvailable( rbuf );
 
156
    if( elementCount > available ) elementCount = available;
 
157
    /* Check to see if read is not contiguous. */
 
158
    index = rbuf->readIndex & rbuf->smallMask;
 
159
    if( (index + elementCount) > rbuf->bufferSize )
 
160
    {
 
161
        /* Write data in two blocks that wrap the buffer. */
 
162
        ring_buffer_size_t firstHalf = rbuf->bufferSize - index;
 
163
        *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
 
164
        *sizePtr1 = firstHalf;
 
165
        *dataPtr2 = &rbuf->buffer[0];
 
166
        *sizePtr2 = elementCount - firstHalf;
 
167
    }
 
168
    else
 
169
    {
 
170
        *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
 
171
        *sizePtr1 = elementCount;
 
172
        *dataPtr2 = NULL;
 
173
        *sizePtr2 = 0;
 
174
    }
 
175
    return elementCount;
 
176
}
 
177
/***************************************************************************
 
178
*/
 
179
ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
 
180
{
 
181
    /* we need to ensure that previous writes are always seen before updating the index. */
 
182
    PaUtil_WriteMemoryBarrier();
 
183
    return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask;
 
184
}
 
185
 
 
186
/***************************************************************************
 
187
** Return elements written. */
 
188
ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount )
 
189
{
 
190
    ring_buffer_size_t size1, size2, numWritten;
 
191
    void *data1, *data2;
 
192
    numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
 
193
    if( size2 > 0 )
 
194
    {
 
195
 
 
196
        memcpy( data1, data, size1*rbuf->elementSizeBytes );
 
197
        data = ((char *)data) + size1*rbuf->elementSizeBytes;
 
198
        memcpy( data2, data, size2*rbuf->elementSizeBytes );
 
199
    }
 
200
    else
 
201
    {
 
202
        memcpy( data1, data, size1*rbuf->elementSizeBytes );
 
203
    }
 
204
    PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten );
 
205
    return numWritten;
 
206
}
 
207
 
 
208
/***************************************************************************
 
209
** Return elements read. */
 
210
ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount )
 
211
{
 
212
    ring_buffer_size_t size1, size2, numRead;
 
213
    void *data1, *data2;
 
214
    numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
 
215
    if( size2 > 0 )
 
216
    {
 
217
        memcpy( data, data1, size1*rbuf->elementSizeBytes );
 
218
        data = ((char *)data) + size1*rbuf->elementSizeBytes;
 
219
        memcpy( data, data2, size2*rbuf->elementSizeBytes );
 
220
    }
 
221
    else
 
222
    {
 
223
        memcpy( data, data1, size1*rbuf->elementSizeBytes );
 
224
    }
 
225
    PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead );
 
226
    return numRead;
 
227
}